Thanks to JohnKiller's suggestion, I realized that .bashrc executes both when a new tty is opened, and when TMUX is opened in a terminal.
For future readers: The $TMUX variable is typically referenced to see if TMUX is running at all, but you could also use "pidof tmux". The $TMUX variable will be populated with something like: "/tmp/tmux-0/default,27389,0" if TMUX is running.
In my particular case, I'm running CentOS 6, and have it set to auto-login with root since it's just a test image. I was able to do that by editing /etc/init/tty.conf:
exec /bin/mingetty --autologin root $TTY
Now that it's set to auto-login, I added the following to /root/.bashrc:
if [[ `tty` == "/dev/tty1" ]] && [[ -z "$TMUX" ]];then
tmux
fi
For newbies reading this, this says "If my terminal is terminal 1, and the $TMUX variable is zero-length, run tmux".
It's followed by:
if [[ -n "$TMUX" ]] && [[ ! -e "/root/.automatic_start_occurred" ]];then
touch /root/.automatic_start_occurred
/usr/bin/hello_world
fi
Again for newbies, this says "If $TMUX is non-zero in length, and the file ".automatic_start_occurred" does not exist (the "!" in the if statement), make the file "/root/.automatic_start_occurred" and then execute "hello_world" in /usr/bin.
This is exactly what I was looking for my system to do - After booting, TTY1 will pop up with TMUX, and the other TTYs will be left alone. When TMUX pops up for the first time, it will execute some arbitrary commands, and never do them again unless the file ".automatic_startup_occurred" is removed.
No local-side tool can do this, because of what the server "sees":
- if you disconnect SSH gracefully, the server will notice this immediately;
- if you just disappear (e.g. by a hard reset), the connection will stay open on the server side until some kind of timeout (compare
ClientAlive*
options, TCP keepalive concept – see this answer for some details).
Even if you intended to use tmux-resurrect
or another tool on the local side, the server doesn't know, doesn't care. It will terminate your long-running code unless you used nohup
or better…
If you can, use tmux
(or screen
) on the server:
- Don't enter
tmux
session on the client.
ssh
to the server.
- Start
tmux
session on the server.
- Launch long-running code there.
- Disconnect anyhow: gracefully or not, with or without detaching from the remote
tmux
.
ssh
again.
- Your
tmux
session is still there (unless something bad happened to the server in the meantime); reattach with tmux a
.
I use tmux
this way on daily basis and I think this is the right way. On my laptop tmux
sessions last for few hours at most, I shut it down every night; but I have access to a couple of servers where my tmux
sessions run for months. When I'm writing this, on one of them there's watch df -h
process running literally for a week in a tmux
session started like two months ago.
Best Answer
For now, there is no specific way to have tmux automatically run commands triggered by
detach
or closing all windows in the session. However, since you already have a wrapper script (I will call thistmux_wrapper
) that opens your desired custom-session, you can easily convert this script to automate cleanup. I do something very similar to this myself here, where I wanted to allow nested tmux sessions if I am attaching through ssh.Since you have a custom experience in mind, you no longer need the
tmux attach ....
or similar commands, so I will assume you always start session for project A by something liketmux_wrapper A
. In your wrapper you probably have a line similar totmux new-session -s A
. Here we can take advantage of the session nameA
. Then, at the end of your wrapper you can have a cleanup switch that only activates if the session is no longer live (i.e. windows/panes are no longer attachable).A simple example
tmux_wrapper
would look something like this:Run it like
tmux_wrapper A
. Now, the cleanup will automatically occur for session A if and only if the session has been completely closed.