Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send Ctrl-C to remote processes started via subprocess.Popen and ssh

How do I send a Ctrl-C to multiple ssh -t processes in Popen() objects?

I have some Python code that kicks off a script on a remote host:

# kickoff.py

# i call 'ssh' w/ the '-t' flag so that when i press 'ctrl-c', it get's
# sent to the script on the remote host.  otherwise 'ctrol-c' would just
# kill things on this end, and the script would still be running on the
# remote server
a = subprocess.Popen(['ssh', '-t', 'remote-host', './script.sh', 'a'])
a.communicate()

That works great, but I need to kick off multiple scripts on the remote host:

# kickoff.py

a = subprocess.Popen(['ssh', '-t', 'remote-host', './script.sh', 'a'])
b = subprocess.Popen(['ssh', '-t', 'remote-host', './script.sh', 'b'])
a.communicate()
b.communicate()

The result of this is that Ctrl-C doesn't reliably kill everything, and my terminal always gets garbled afterwards (I have to run 'reset'). So how can I kill both remote scripts when the main one is killed?

Note: I'm trying to avoid logging into the remote-host, searching for 'script.sh' in the process list, and sending a SIGINT to both of the processes. I just want to be able to press Ctrl-C on the kickoff script, and have that kill both remote processes. A less optimal solution may involve deterministically finding the PID's of the remote scripts, but I don't know how to do that in my current set-up.

Update: the script that gets kicked off on the remote server actually starts up several children processes, and while killing the ssh does kill the original remote script (probably b/c of SIGHUP), the children tasks are not killed.

like image 250
aaronstacy Avatar asked Jan 12 '11 13:01

aaronstacy


1 Answers

The only way I was able to successfully kill all of my child processes was by using pexpect:

a = pexpect.spawn(['ssh', 'remote-host', './script.sh', 'a'])
a.expect('something')

b = pexpect.spawn(['ssh', 'remote-host', './script.sh', 'b'])
b.expect('something else')

# ...

# to kill ALL of the children
a.sendcontrol('c')
a.close()

b.sendcontrol('c')
b.close()

This is reliable enough. I believe someone else posted this answer earlier, but then deleted the answer, so I will post it in case someone else is curious.

like image 96
aaronstacy Avatar answered Sep 29 '22 05:09

aaronstacy