4

Is there any way of attaching a console's STDIN/STDOUT to an already running process?

Use Case:

I have a python script which runs another python script on the command line using popen.

Let's say foo.py runs popen to run python bar.py.

Then bar.py blocks on input. I can get the PID of python bar.py. Is there any way to attach a new console to the running python instance in order to be able to work interactively with it? This is specifically useful because I want to run pdb inside of bar.py.

Mike Pennington
  • 41,899
  • 19
  • 136
  • 174
Jamie Wong
  • 18,104
  • 8
  • 63
  • 81

2 Answers2

4

No way. But you can modify the way you start bar.py in order to be prepared to take over stdin and stdout.

A simple method would be to just create named pipes and supply these as stdin/stdout in the Popen call. You may then connect to these pipes from you shell (exec <pipe1 >pipe2) and interact. This has the disadvantage that you must connect to the pipes to see what the process is doing. While you can work around that by using tee on a log file, depending on the terminal capability demands of bar.py this kind of interaction may not be the greatest pleasure.

A better way could be to incorporate a terminal multiplexer like GNU screen or tmux into you process tree. These tools can create a virtual terminal in which the application is run. You may then at any time attach and detach any other terminal to this terminal buffer. In your specific case, foo.py would run screen or tmux, which will run python bar.py in a complete (VT100) terminal emulation. Maybe this will solve your problem.

Ulf Rompe
  • 919
  • 6
  • 8
  • This sounds promising - I can get input/output working using `Popen` with named pipes, but I'm not sure how to use `exec`. I set up two named pipes using `os.mkfifo('/tmp/testout')` and `os.mkfifo('/tmp/testin')`, then running `Popen(cmd, stdout=open('/tmp/testout', 'a'), stdin=open('/tmp/testin', 'r'))`. I tried `exec > /tmp/testin < /tmp/testout`, but it doesn't look like it's doing anything – Jamie Wong May 04 '12 at 21:46
  • Using `screen` worked! What a beautiful solution - thanks! I'd still be interested to know how to use exec, if you're so inclined – Jamie Wong May 04 '12 at 22:01
0

You cannot redirect stdin or stdout for a running process. You can, however, add code to your caller -- foo.py -- that will read from foo.py's stdin and send it to bar.py's stdout, and vice-versa.

In this model, foo.py would connect bar.py's stdin and stdout to pipes and would be responsible for shuttling data between those pipes and the real stdin/stdout.

larsks
  • 277,717
  • 41
  • 399
  • 399
  • FYI apparently it is possible to redirect stdin and stdout for a running process in some circumstances: http://stackoverflow.com/questions/593724/redirect-stderr-stdout-of-a-process-after-its-been-started-using-command-lin (But this doesn't give me interactivity) – Jamie Wong May 04 '12 at 19:59
  • I think, after looking at your link, that the answer is still "no". You can do a lot of things if you're willing to attach `gdb` to your process, but outside of your development environment they're not very practical. – larsks May 04 '12 at 20:08