Cannot start two interactive shells using popen

前端 未结 2 1970
攒了一身酷
攒了一身酷 2021-01-21 11:50

I have the following Python snippet, and cannot explain why it behaves the way it does.

import subprocess  
bash1 = subprocess.Popen([\"/bin/bash\",\"-l\", \"-i\         


        
相关标签:
2条回答
  • 2021-01-21 12:01

    Answer to question 1:

    This is because an interactive bash shell expects to be attached to a terminal (the 'controlling terminal') and acquire it in order to process job control interrupts (e.g. Control-Z). The second invocation tries to acquire the terminal but can't, so gets temporarily suspended.

    Answer to question 2:

    communicate writes its argument to the stdin pipe of the child process and then closes it. Bash terminates when its stdin is exhausted (it is like entering Control-D in a bash terminal session).

    If you want to keep the bash child process running, then write to its stdin directly rather than use communicate as follows:

    bash1.stdin.write("echo 'works1'\n")
    

    You do need to add the newline if you want the command to actually execute, by the way.

    A solution:

    If you want to run two or more interactive shells, you should setup the stdin of each shell to be a pseudo-terminal rather than a subprocess PIPE.

    0 讨论(0)
  • 2021-01-21 12:03

    According to the isedev hint, I opened 2 pseudoterminals. Important thing is that master process (this python script) reads and writes on the master PTY file, while child subprocess uses slave file as stdin, stdout and stderr. Bottom part of the code is just for testing how everything works.

    import subprocess
    import os
    import pty
    import select
    import time
    
    # according to> http://fleckenzwerg2000.blogspot.com/2011/10/running-and-controlling-gnu-screen-from.html
    (master1, slave1) = pty.openpty()
    bash1 = subprocess.Popen(["bash", "-l", "-i"], stdin=slave1, stdout=slave1, stderr=slave1)
    (master2, slave2) = pty.openpty()
    bash2 = subprocess.Popen(["bash", "-l", "-i"], stdin=slave2, stdout=slave2, stderr=slave2)
    data = "echo 'bla'\n"
    
    ## taken from> http://stackoverflow.com/questions/14564904/how-to-send-tab-key-to-python-subprocesss-stdin
    def write_all(masterPTY, data):
        """Successively write all of data into a file-descriptor."""
        while data:
            chars_written = os.write(masterPTY, data)
            data = data[chars_written:]
        return data
    
    def read_all(masterPTY):
        r,w,x = select.select([masterPTY], [], [], 10)
        if r:
            data = os.read(masterPTY, 1024)
            return data
    
    
    write_all(master1, "echo 'bla1'\n")
    write_all(master2, "echo 'bla2'\n")
    time.sleep(1)
    print read_all(master1)
    write_all(master1, "echo 'bla1'\n")
    time.sleep(1)
    
    print read_all(master2)
    
    time.sleep(1)
    
    os.close(master1)
    os.close(slave1)
    os.close(master2)
    os.close(slave2)
    
    bash1.terminate()
    bash2.terminate()
    
    print "OK"
    

    That is it. Hope it helps someone!

    0 讨论(0)
提交回复
热议问题