2

I'm attempting to basically create a shell in python using subprocess.Popen. As boilerplate code for testing purposes, this is what I have:

if __name__ == '__main__':
    ps = subprocess.Popen(
        input('command? '),
        shell=True,
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True
    )

    print(ps.stdout.read())
    time.sleep(1) # provide enough time to register completion if the command is a one-off, like dir or echo
    while ps.poll() == None: # ps.poll() returns None if still running
        try:
            # method one
            ps.stdin.write(input())
            ps.communicate()
            print(ps.stdout.read())

            # method two
            ps.stdin.write(input())
            print(ps.communicate()[0])

            # method three
            print(ps.communicate(input())[0])
        except:
            continue

    print('Process Finished')

Each method is a different (failed) attempt.

For commands like python which should open the python CLI interpreter, this completely fails. However, for one-off commands like dir or ls or even running python -c "<some python>" it works just fine.

CLI log:

C:\Users\nj2u2\Desktop\test>python test.py
command? echo hello
hello

Process Finished

C:\Users\nj2u2\Desktop\test>python test.py
command? dir
 Volume in drive C has no label.
 Volume Serial Number is D6B7-6B8D

 Directory of C:\Users\nj2u2\Desktop\test

07/03/2020  12:26 AM    <DIR>          .
07/03/2020  12:26 AM    <DIR>          ..
07/03/2020  08:20 PM             6,811 subprocess_plus.py
07/04/2020  12:55 PM               580 test.py
07/03/2020  08:25 PM    <DIR>          __pycache__
               2 File(s)          7,391 bytes
               3 Dir(s)  1,487,446,302,720 bytes free

Process Finished

C:\Users\nj2u2\Desktop\test>python test.py
command? python


After that last command, python, it just hangs at print(ps.stdout.read()).

I'd like to know why it's hanging, and how I can fix it.

1
  • 1
    If your script works with some commands and not others, perhaps the issue is not related to your script but to how those "failing" commands are implemented. Have you tried simply opening the python CLI as a subprocess, and sending it a short, hard-coded command? Does that work? If it doesn't then your script is not going to work, and there is nothing you can do about it. Programs are not required to support the customary stdin/stdout protocol, so expect that some of them will not work with your approach. Commented Jul 4, 2020 at 3:01

1 Answer 1

1

The communicate method can only be used for non interactive commands because it sends a one shot input and then waits for the sub process to terminate. That is the reason that it can only work with what you call one-off commands.

But beware, pipes do not support the terminal discipline in which a read call automatically flushes the output, and where a new line causes a read to return immediately. So nothing guarantees that you can use that to provide interactive IO to the python CLI interpretor. Pipes are just streams, and can be buffered so you can just be sure that all the input will be delivered, and that when the output channels will be closed (i.e. when the sub-process command will terminate) you will receive all the output. The way input and output are intermixed depends on the way the sub-process command is programmed. If it willingly flushes its output before reading, and you do the same in your code, then interactive processing is possible, but if it does not, there is no way to expect to receive something after each end of line.

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.