Discussion:
Blocking ctrl-c to os.popen() or os.system()
Erik Max Francis
2003-01-05 05:34:27 UTC
Permalink
I am executing a command from python via os.popen(). While the
command is executing, if I type ctrl-c, the command receives the
interrupt. I would like to block the ctrl-c from the command and I've
1)Using python's signal module to ignore SIGINT. This causes python
to ignore SIGINT, but a ctrl-c that is typed during the popen() call
still goes to the command.
2)Adding "< /dev/null" to the os.popen() call. This doesn't help.
3)Using popen2() and immediately closing the stdin file. This also
doesn't work.
Any suggestions would be greatly appreciated!
The problem here (which other responders failed to identify) is that
it's the spawned program that's getting the INT signal, not the Python
program launching it. Signals are really independent of stdin/stdout,
so that's why your redirection and file closing isn't helping.

Unfortunately, I don't think there's any pretty solution to your
problem. What you probably need to do is write a wrapper program that
intercepts the INT signal and ignores it (presuming that's what you
actually want to do). This would be similar to the nohup program (which
does something analogous, but for the HUP signal).

You can write a little script to do it, with bash, ksh, zsh, or
varieties. In zsh it would look like:

#!/bin/zsh -f

function TRAPINT () { }

"$@"

The other shells have similar mechanisms, I believe involving a trap
builtin.

Unfortunately you're probably going to be forced to use a wrapper script
for portability, since with os.popen (or os.system) you're not
guaranteed which shell is going to get run, so you can't do the trapping
inline.

Note that this won't stop other signals, such as TERM, and that nothing
can stop KILL.
--
Erik Max Francis / max at alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ War is a continuation of policy by other means.
\__/ Karl von Clausewitz
CAGE / http://www.alcyone.com/pyos/cage/
A cellular automaton simulation system in Python.
Erik Max Francis
2003-01-05 07:11:32 UTC
Permalink
How about using a thread?
That wouldn't work, since -- as the original poster pointed out several
times now -- it's a separate program that he's running that's receiving
the SIGINT, not the Python program driving it.
--
Erik Max Francis / max at alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ We'll have to make our own luck from now on.
\__/ Louis Wu
Bosskey.net: Quake III Arena / http://www.bosskey.net/q3a/
A personal guide to Quake III Arena.
Donn Cave
2003-01-05 19:15:32 UTC
Permalink
Quoth Erik Max Francis <max at alcyone.com>:
...
| The problem here (which other responders failed to identify) is that
| it's the spawned program that's getting the INT signal, not the Python
| program launching it. Signals are really independent of stdin/stdout,
| so that's why your redirection and file closing isn't helping.

True. It is related to terminal I/O, but not directly enough to depend
on the actual open files. Instead, it's inherited from tty processes
through the terminal process group, in systems that use Berkeley job
control (i.e., all modern UNIX & clones like Linux.)

When system or popen starts a new process, it inherits the caller's
process group, and if the caller is subject to signals from the
terminal driver like <ctrl>C, then so will the new process. (This
is also true of processes started in a shell script, incidentally,
so I think you will find that "trap" won't really save them.)

posix.setpgrp() establishes a new process group. It has to be invoked
from the child fork, so one would need to do something like copy
os.spawnv or popen2.Popen* and modify it accordingly.

Donn Cave, donn at drizzle.com
pythonhda
2003-01-05 06:02:33 UTC
Permalink
On Sat, 04 Jan 2003 21:34:27 -0800
Post by Erik Max Francis
I am executing a command from python via os.popen(). While the
command is executing, if I type ctrl-c, the command receives the
interrupt. I would like to block the ctrl-c from the command and I've
1)Using python's signal module to ignore SIGINT. This causes python
to ignore SIGINT, but a ctrl-c that is typed during the popen() call
still goes to the command.
2)Adding "< /dev/null" to the os.popen() call. This doesn't help.
3)Using popen2() and immediately closing the stdin file. This also
doesn't work.
Any suggestions would be greatly appreciated!
The problem here (which other responders failed to identify) is that
it's the spawned program that's getting the INT signal, not the Python
program launching it. Signals are really independent of stdin/stdout,
so that's why your redirection and file closing isn't helping.
Unfortunately, I don't think there's any pretty solution to your
problem. What you probably need to do is write a wrapper program that
intercepts the INT signal and ignores it (presuming that's what you
actually want to do). This would be similar to the nohup program (which
does something analogous, but for the HUP signal).
You can write a little script to do it, with bash, ksh, zsh, or
#!/bin/zsh -f
function TRAPINT () { }
The other shells have similar mechanisms, I believe involving a trap
builtin.
Unfortunately you're probably going to be forced to use a wrapper script
for portability, since with os.popen (or os.system) you're not
guaranteed which shell is going to get run, so you can't do the trapping
inline.
Note that this won't stop other signals, such as TERM, and that nothing
can stop KILL.
--
Erik Max Francis / max at alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ War is a continuation of policy by other means.
\__/ Karl von Clausewitz
CAGE / http://www.alcyone.com/pyos/cage/
A cellular automaton simulation system in Python.
How about using a thread?
Threads interact strangely with interrupts: the KeyboardInterrupt
exception will be received by an arbitrary thread. (When the
signal module is available, interrupts always go to the main
thread.)

So you would have something like this:

worker = newThread()
worker.start()
while worker.isAlive():
try:
worker.join() # should block here until the thread is done
except KeyboardInterrupt:
print "still running, hold on..."
Michael Hudson
2003-01-14 14:40:22 UTC
Permalink
I am executing a command from python via os.popen(). While the
command is executing, if I type ctrl-c, the command receives the
interrupt. I would like to block the ctrl-c from the command and I've
1)Using python's signal module to ignore SIGINT. This causes python
to ignore SIGINT, but a ctrl-c that is typed during the popen() call
still goes to the command.
That's surprising, to me at least. I thought the exec* functions left
SIG_IGN signal destinations alone. Does popen reset them? The linux
manpage doesn't give any indication of doing so.

Cheers,
M.
--
A.D. 1517: Martin Luther nails his 95 Theses to the church door and
is promptly moderated down to (-1, Flamebait).
-- http://slashdot.org/comments.pl?sid=01/02/09/1815221&cid=52
(although I've seen it before)
Sandeep Gupta
2003-01-05 04:29:10 UTC
Permalink
Thanks, Chad. I was not clear in my previous message.

I am running on Linux, but the script I'm writing will also be using on
Win2k.

What I meant was I start the command and programatically wait for it to
finish. I wait for the command to finish by doing an f.read() on the stdout
returned from popen*(). While I am waiting for it to finish, if the user
types ctrl-c, the command receives the interrupt.

I also posted the question to the unix.shell newsgroup. Apparently, the
command subprocess is allowed to turn on the signal again, and that may be
happening in my case. If I turn off signal handling for SIGINT, and then
run the command "ls -R / | wc -l" (which takes a minute to run on my
system), then I am not able to interrupt the command. But if my command is
"cvs diff", cvs receives the ctrl-c.

Any other suggestions?
Thanks

"Chad Netzer" <cnetzer at mail.arc.nasa.gov> wrote in message
I am executing a command from python via os.popen(). While the
command is executing, if I type ctrl-c, the command receives the
interrupt.
What is your system? On Linux, with a trivial (and perhaps foolish)
example
~~~~~~~~~~~~~~~~~~~~~~~~
import os
import time
cmd_str = "sleep 20"
print 'Running "%s"' % cmd_str
os.popen2( cmd_str )
print "Python now sleeping for 20 seconds."
time.sleep(20)
print "ctrl-c was pressed"
~~~~~~~~~~~~~~~~~~~~~~~~
$ python popen_test.py
Running "sleep 20"
Python now sleeping for 20 seconds.
ctrl-c was pressed
Note - I pressed ctrl-c to get that result. :)
--
Bay Area Python Interest Group - http://www.baypiggies.net/
Chad Netzer
cnetzer at mail.arc.nasa.gov
Jarkko Torppa
2003-01-05 04:54:10 UTC
Permalink
Post by Sandeep Gupta
I am running on Linux, but the script I'm writing will also be using on
Win2k.
What I meant was I start the command and programatically wait for it to
finish. I wait for the command to finish by doing an f.read() on the stdout
returned from popen*(). While I am waiting for it to finish, if the user
types ctrl-c, the command receives the interrupt.
But if my command is "cvs diff", cvs receives the ctrl-c.
Any other suggestions?
If your cvs is doing remote stuff it's most propably ssh/rsh that is
trying to grab terminal directly, ssh has some flags that
might help.

This might also help, unless it also enables tty signal processing

import termios,TERMIOS,copy,sys
oat=termios.tcgetattr(sys.stdin.fileno())
at=termios.tcgetattr(sys.stdin.fileno())
at[3]=at[3] & ~TERMIOS.ISIG
termios.tcsetattr(sys.stdin.fileno(),TERMIOS.TCSANOW,at)
(popen here)
termios.tcsetattr(sys.stdin.fileno(),TERMIOS.TCSANOW,oat)

This most propably does not work on windows
--
Jarkko Torppa
Sandeep Gupta
2003-01-05 02:41:45 UTC
Permalink
Unfortunately, python doesn't see the ctrl-c when it is typed during the
command, so there is no KeyboardInterrupt.

Thanks for the idea...

"pythonhda" <pythonhda at yahoo.com.replacepythonwithlinux> wrote in message
Maybe you can try to catch the exception?
.....
print "I'm not done yet"
On 4 Jan 2003 14:00:35 -0800
I am executing a command from python via os.popen(). While the
command is executing, if I type ctrl-c, the command receives the
interrupt. I would like to block the ctrl-c from the command and I've
1)Using python's signal module to ignore SIGINT. This causes python
to ignore SIGINT, but a ctrl-c that is typed during the popen() call
still goes to the command.
2)Adding "< /dev/null" to the os.popen() call. This doesn't help.
3)Using popen2() and immediately closing the stdin file. This also
doesn't work.
Any suggestions would be greatly appreciated!
Thanks
Sandeep
Sandeep Gupta
2003-01-04 22:00:35 UTC
Permalink
I am executing a command from python via os.popen(). While the
command is executing, if I type ctrl-c, the command receives the
interrupt. I would like to block the ctrl-c from the command and I've
tried the following:

1)Using python's signal module to ignore SIGINT. This causes python
to ignore SIGINT, but a ctrl-c that is typed during the popen() call
still goes to the command.

2)Adding "< /dev/null" to the os.popen() call. This doesn't help.

3)Using popen2() and immediately closing the stdin file. This also
doesn't work.

Any suggestions would be greatly appreciated!

Thanks
Sandeep
pythonhda
2003-01-05 02:38:12 UTC
Permalink
Maybe you can try to catch the exception?

while doing_something:
try:
.....
except KeyboardInterrupt:
print "I'm not done yet"



On 4 Jan 2003 14:00:35 -0800
I am executing a command from python via os.popen(). While the
command is executing, if I type ctrl-c, the command receives the
interrupt. I would like to block the ctrl-c from the command and I've
1)Using python's signal module to ignore SIGINT. This causes python
to ignore SIGINT, but a ctrl-c that is typed during the popen() call
still goes to the command.
2)Adding "< /dev/null" to the os.popen() call. This doesn't help.
3)Using popen2() and immediately closing the stdin file. This also
doesn't work.
Any suggestions would be greatly appreciated!
Thanks
Sandeep
Chad Netzer
2003-01-05 03:31:29 UTC
Permalink
I am executing a command from python via os.popen(). While the
command is executing, if I type ctrl-c, the command receives the
interrupt.
What is your system? On Linux, with a trivial (and perhaps foolish) example
it seems that the Python interpreter does indeed get the ctrl-c:

~~~~~~~~~~~~~~~~~~~~~~~~
import os
import time

if __name__ == '__main__':
cmd_str = "sleep 20"
print 'Running "%s"' % cmd_str
os.popen2( cmd_str )

print "Python now sleeping for 20 seconds."
try:
time.sleep(20)
except KeyboardInterrupt:
print "ctrl-c was pressed"
~~~~~~~~~~~~~~~~~~~~~~~~

$ python popen_test.py
Running "sleep 20"
Python now sleeping for 20 seconds.
ctrl-c was pressed


Note - I pressed ctrl-c to get that result. :)
--
Bay Area Python Interest Group - http://www.baypiggies.net/

Chad Netzer
cnetzer at mail.arc.nasa.gov
Loading...