在子进程linux

时间:2016-04-21 21:17:45

标签: python linux

我有一个sh文件,我需要在目标linux框中安装它。所以我正在为sh文件编写自动安装的过程,这需要用户提供大量的输入。例如,我做的第一件事./file.sh它将显示一个大的paragaraph并要求用户按Enter。我被困在这个地方。如何将关键数据发送到子流程。这是我尝试过的。

import subprocess

def runProcess(exe):
    global p
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while(True):
      retcode = p.poll() #returns None while subprocess is running
      line = p.stdout.readline()
      yield line
      if(retcode is not None):
        break

for line in runProcess('./file.sh'.split()):
    if '[Enter]' in line:
        print line + 'got it'
        p.communicate('\r')

如果我的理解是错误的,请纠正我,请原谅我是否重复。

2 个答案:

答案 0 :(得分:2)

如果您需要发送一堆换行符,则需要:

  1. 确保stdin的{​​{1}}是管道
  2. 发送换行符而不会导致死锁
  3. 您当前的代码都没有。可能有用的东西(假设他们不使用需要在tty中直接交互的API,而不仅仅是阅读Popen):

    stdin

    对于需要自定义响应的情况,您需要在父线程和馈线线程之间添加通信,这会使这更加丑陋,并且只有在子进程正确刷新其输出时才有效即使未连接到终端,它也会提示您。您可以执行以下操作来定义全局队列:

    import subprocess
    import threading
    
    def feednewlines(f):
        try:
            # Write as many newlines as it will take
            while True:
                f.write(b'\n')  # Write newline, not carriage return
                f.flush()       # Flush to ensure it's sent as quickly as possible
        except OSError:
            return   # Done when pipe closed/process exited
    
    def runProcess(exe):
        global p
        # Get stdin as pipe too
        p = subprocess.Popen(exe, stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        # Use thread to just feed as many newlines as needed to stdin of subprocess
        feeder = threading.Thread(target=feednewlines, args=(p.stdin,))
        feeder.daemon = True
        feeder.start()
    
        # No need to poll, just read until it closes stdout or exits
        for line in p.stdout:
            yield line
        p.stdin.close()  # Stop feeding (causes thread to error and exit)
        p.wait()         # Cleanup process
    
    # Iterate output, and echo when [Enter] seen
    for line in runProcess('./file.sh'.split()):
        if '[Enter]' in line:
            print line + 'got it'
    

    然后将进纸器功能更改为:

    import queue   # Queue on Python 2
    
    feederqueue = queue.Queue()
    

    并将全局代码更低地更改为:

    def feednewlines(f):
        try:
            while True:
                f.write(feederqueue.get())
                f.flush()
        except OSError:
            return
    

答案 1 :(得分:1)

当命令行程序在后台运行时,它们在终端中运行时运行方式不同。如果程序附加到终端,则它们以交互式线路模式运行,期望用户交互。如果stdin是文件或管道,则它们以块模式运行,其中写入被延迟,直到缓冲某个块大小。您的程序永远不会看到[Enter]提示符,因为它使用管道并且数据仍在子进程输出缓冲区中。

python pexpect模块通过模拟终端并允许您通过一系列" expect"来解决这个问题。语句。

假设我们想要运行一个测试程序

#!/usr/bin/env python3
data = input('[Enter]')
print(data)
它非常无聊。它会提示输入数据,打印数据然后退出。我们可以使用pexpect

运行它
#!/usr/bin/env python3

import pexpect

# run the program
p = pexpect.spawn('./test.py')
# we don't need to see our input to the program echoed back
p.setecho(False)
# read lines until the desired program output is seen
p.expect(r'\[Enter\]')
# send some data to the program
p.sendline('inner data')
# wait for it to exit
p.expect(pexpect.EOF)
# show everything since the previous expect
print(p.before)

print('outer done')