creating ssh connections that will cleanly terminate in shell scripts
i’ve noticed that if you write a script that does something not too different than
for i in `cat servers.txt`; do
ssh $i run some command
done
this will take a while since all of the ssh connections will run
one-by-one. alternatively, you could do background all the ssh
connections with &
. but this is problematic because if you decided
that you want to prematurely terminate those commands, sending a
SIGINT to your script will not terminate those processes.
sometimes, too, even if you terminate your ssh connection, the remote
processes will keep running. one way to get around this is to run ssh
with the -t
flag which creates a psuedo-tty. this works well, if you
open a terminal and run ssh -t remote sleep 3600
. closing the
terminal or sending a SIGINT to the ssh process will also terminate
sleep
on the remote machine. if you try to background this process,
it will hang until you bring it back to the foreground. so, there must
be something else.
and there is. in the man page for ssh, it has a slightly cryptic
message under -t
, saying, “Multiple -t
options force tty
allocation, even if ssh
has no local tty.”
anyway, the trick is to do something like this:
ssh -tt remote sleep 3600 </dev/null &
now it will run in the background without any problems. sending it a
SIGINT will terminate sleep
on the remote machine as well. so this
is great.
the </dev/null
along with the cryptic hint in the man page make
sense, though. what happens is we are forcing ssh
to create a tty,
but because we are not attached to a local tty, there is no stdin and
things choke. so opening up that pipe with /dev/null
will not stall
the ssh
process and it can continue running.
weird.
but awesome.
now you can run many commands, simulataneously, on many machines. and
if you goofed up, you can just terminate the script with a ^c
.
this is a small example of how i used it:
#!/bin/bash
trap "kill -1 -$$" SIGINT
for i in `cat objmanblasters{,}{,}{,}`; do
ssh $i -tt objmanblast </dev/null &
done
sleep infinity