I want to create a session with the name - generalAnd I want to have two windows in it -
- win1
- win2
And I need to run script1 in win1 and script2 in win2
Currently I have written the script like -
SESSION="general"
echo $SESSION
tmux attach-session -d -t $SESSION || tmux new-session -s $SESSION -n win1 -c /my/path/ ./script1.sh
tmux new-window -n win2 tel_csrWith this script, I am able to create a session with the name general. But only one window is coming up with the name win1 and running the script - script1.sh.
The second statement is not kicking in. What is wrong with the above script.
Note: script1.sh triggers a server program, so it doesn't return I guess.
1 Answer
Analysis
What is wrong with the above script?
Run sleep 5; echo done. Are you surprised echo works only after sleep exits? The shell runs the two commands in sequence, not in parallel.
Now run less /etc/fstab; echo done. You will see done only after you exit from less (with Q).
tmux new-session; tmux new-window is no different.
In your script tmux attach-session or tmux new-session attaches to a session. One or the other tmux command becomes a tmux client and it runs until you detach. The script waits for this tmux to exit before executing the next command. You cannot see the effect of tmux new-window before you detach because this command has not been executed yet.
If you detach then you will allow the script to continue. Do it without destroying the session, attach again and you will see the new window.
Solution
Attach after you set everything up.
Set everything up using commands that don't attach to the session (e.g. tmux new-session -d). If you eventually want to attach then tmux attach-session should be the last command in the script (unless you deliberately want to do something extra after you detach). This example (run it outside of tmux) will attach to a session where an additional window already exists:
tmux new-session -d
tmux new-window
tmux attach-sessionIn general you want to name and target the exact session, window etc. And you want some logic to handle a situation when the named session exists etc.
Alternative
An alternative approach is to invoke some "maintenance" commands from a subshell running asynchronously and attach early from the main shell, with the "maintenance" part still running in parallel. Example (run it outside of tmux):
(tmux new-session -d; sleep 5; tmux new-window) & sleep 2; tmux attach-sessionsleep 5 simulates commands that take time. With the previous solution you would have to wait until all of them finish. Here you don't have to wait that long, you attach before tmux new-window runs. This way you can actually see a new window popping out in tmux.
This method has serious disadvantages though:
- You can interact with tmux even before everything is set up. By changing the current pane (or window etc.) or destroying some pane (or window etc.) you can cause the "maintenance" commands to target the wrong pane (or window etc.) or to fail; unless they are carefully crafted to handle such situation.
- Race conditions. In the above example
sleep 2delaysattach-sessionso it hopefully runs afternew-session. Even withsleep 2(or even withsleep 2000) there is no guaranteenew-sessionruns first, only high probability. There istmux wait-forto handle such situations (but using it right can be tricky; see "Dealing with race conditions" in this another answer of mine).