【问题标题】:python subprocess.call output is not interleavedpython subprocess.call 输出不交错
【发布时间】:2013-11-21 05:01:06
【问题描述】:

我有一个运行其他 shell 脚本的 python (v3.3) 脚本。我的 python 脚本还打印诸如“关于运行脚本 X”和“完成运行脚本 X”之类的消息。

当我运行我的脚本时,我会将 shell 脚本的所有输出与我的打印语句分开。我看到这样的东西:

All of script X's output
All of script Y's output
All of script Z's output
About to run script X
Done running script X
About to run script Y
Done running script Y
About to run script Z
Done running script Z

我运行 shell 脚本的代码如下所示:

print( "running command: " + cmnd )
ret_code = subprocess.call( cmnd, shell=True )
print( "done running command")

我写了一个基本的测试脚本, *没有*看到这种行为。这段代码符合我的预期:

print("calling")
ret_code = subprocess.call("/bin/ls -la", shell=True )
print("back")

知道为什么输出没有交错吗?

【问题讨论】:

    标签: python subprocess


    【解决方案1】:

    谢谢。这可行,但有一个限制 - 在命令完成之前您看不到任何输出。我从另一个使用 popen 的问题 (here) 中找到了答案,但也让我可以实时查看输出。这是我最终得到的结果:

    import subprocess
    import sys
    
    cmd = ['/media/sf_git/test-automation/src/SalesVision/mswm/shell_test.sh', '4', '2']
    print('running command: "{0}"'.format(cmd))  # output the command.
    # Here, we join the STDERR of the application with the STDOUT of the application.
    process = subprocess.Popen(cmd, bufsize=1, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    for line in iter(process.stdout.readline, ''):
        line = line.replace('\n', '')
        print(line)
        sys.stdout.flush()
    process.wait()                   #  Wait for the underlying process to complete.
    errcode = process.returncode      #  Harvest its returncode, if needed.
    print( 'Script ended with return code of: ' + str(errcode) )
    

    这使用 Popen 并允许我查看被调用脚本的进度。

    【讨论】:

    • 注意:在 Python 3.3 上,您可以使用 for line in process.stdout: 代替 iter(...)。此外,您可以使用print(line, end='', flush=True) 代替line.replace('\n',''); print(line); sys.stdout.flush() 或使用line = line.rstrip('\n')。循环后调用process.stdout.close()
    【解决方案2】:

    它与 STDOUT 和 STDERR 缓冲有关。您应该使用subprocess.PopenSTDOUTSTDERR 从您的子进程重定向到您的应用程序。然后,根据需要,输出它们。示例:

    import subprocess
    
    cmd = ['ls', '-la']
    print('running command: "{0}"'.format(cmd))  # output the command.
    # Here, we join the STDERR of the application with the STDOUT of the application.
    process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    process.wait()  # Wait for the underlying process to complete.
    out, err = process.communicate()  # Capture what it outputted on STDOUT and STDERR
    errcode = process.returncode  # Harvest its returncode, if needed.
    print(out)
    print('done running command')
    

    此外,除非确实需要,否则我不会使用shell = True。它强制子进程启动整个 shell 环境只是为了运行一个命令。通常最好直接注入到Popen的env参数中。

    【讨论】:

    • 谢谢。这可行,但有一个限制 - 在命令完成之前您看不到任何输出。我从另一个使用 popen 的问题中找到了答案,但也让我可以实时查看输出。这是我最终得到的结果:
    • 呃。忽略我之前的评论。我很蹩脚 - 我不知道如何在评论中发布代码。
    • 如果cmd 产生足够的输出,那么你的代码就会死锁。如果您使用subprocess.PIPE,您应该排空管道。在process.communicate() 之前删除process.wait()
    猜你喜欢
    • 2011-10-19
    • 2015-04-26
    • 1970-01-01
    • 1970-01-01
    • 2015-04-07
    • 2012-05-02
    • 1970-01-01
    • 2014-05-18
    • 2018-11-01
    相关资源
    最近更新 更多