0

I've been reading up on a lot of documentations but am still not sure what I'm doing wrong.

So I have a separate shell script that fires up a separate server then the one I'm working on. Once the server is connected, I want to run ls and that's it. However, for some reason stdin=subprocess.PIPE is preventing the Popen command from terminating so that the next line could execute. For example because the code is stuck I'll Ctrl+C but I'll get an error saying that wait() got a keyboard interrupt. Here's an example code:

import subprocess
from time import sleep

p1 = subprocess.Popen("run_server", 
                      stdout = subprocess.PIPE, 
                      stdin = subprocess.PIPE)
#sleep(1)
p1.wait()
p1.communicate(input = "ls")[0]"

If I replace p1.wait() with sleep(1), the communicate command does run and displays ls, but the script that runs the server detects eof on tty and terminates it self. I must have some kind of wait between Popen and communicate because the server script will terminate for the same reason.

3
  • Is the "run_server" command directly what you would put into shell? No ./run_server or anything? Commented Jun 24, 2015 at 21:51
  • @SBHayes Yes, the run_server is all. Commented Jun 24, 2015 at 21:54
  • Ok, I think I understand your question better now. When the script calling Popen terminates, it will close all its children processes too. To keep your server running you have to detach the process somehow. Perhaps a double fork or something similar. Commented Jun 24, 2015 at 22:05

2 Answers 2

1

p.wait() does not return until the child process is dead. While the parent script is stuck on p.wait() call; your child process expects input at the same time -- deadlock. Then you press Ctrl+C in the shell; it sends SIGINT signal to all processes in the foreground process group that kills both your parent Python script and run_server subprocess.

You should drop the .wait() call:

#!/usr/bin/env python
from subprocess import Popen, PIPE

p = Popen(["run_server"], stdout=PIPE, stdin=PIPE)
output = p.communicate(b"ls")[0]

Or in Python 3.4+:

#!/usr/bin/env python3
from subprocess import check_output

output = check_output(["run_server"], input=b"ls")

If you want to run several commands then pass them all at once:

input = "\n".join(["ls", "cmd2", "etc"]) # with universal_newlines=True

As you know from reading the subprocess docs, p.communicate() waits for the child process to exit and therefore it should be called at most once. As well as with .wait(), the child process is dead after .communicate() has returned.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I only had the wait call because of the nature of run_server script, but in the end joining the list of commands turned out to work fine before the script terminated itself. Thanks a bunch!
0

The fact that when you Ctrl+C and your traceback says you were stuck in wait() means the next line is executing, the next line is wait(). wait() won't return until your p1 process returns. However, it seems your p1 process won't return until you send it a command, 'ls' in your case. Try sending the command then calling wait().:

import subprocess
from time import sleep

p1 = subprocess.Popen("run_server", 
                      stdout = subprocess.PIPE, 
                      stdin = subprocess.PIPE)
#sleep(1)
p1.communicate(input = "ls")[0]"
p1.wait()

Otherwise, make sure your "run_server" script terminates so your script can advance past p1.wait()

3 Comments

same issue as I've mentioned above. Because p1 still hasn't terminated yet (at least according to the run_server script it hasn't), it'll take the ls as an interrupt and terminate the run_server script and exit the server.
@Krin123 Can you explain that again? I thought you wanted to send "ls" and get the script to end afterwards?
sorry, I guess what I said was misleading. For now, all I want is ls since it's the simplest thing to run, but after I would also like to run more command lines. So the script ending is not desirable since I have many more command lines to run.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.