【问题标题】:How to disable stdout buffer when running shell运行shell时如何禁用标准输出缓冲区
【发布时间】:2019-09-07 00:40:40
【问题描述】:

我正在使用 Python 调用带有

的 Shell 脚本
def run_command(cmd):
    print "Start to run: " + cmd
    run = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while True:
        line = run.stdout.readline().decode()[:-1]
        if line == '' and run.poll() is not None:
            break
        print line # print the log from shell
    recode = run.returncode
    if recode != 0:
        raise Exception("Error occurs!")

    print "End to run: " + cmd

然后我跑

run_command("sh /home/tome/a.sh")

我注意到 a.sh 的控制台输出不是实时的,看起来有一个用于 stdout 的缓冲区,当 stdout 缓冲区已满时,就会打印输出。

我会问如何在我的脚本 a.sh 中禁用 shell 标准输出缓冲区

谢谢!

【问题讨论】:

    标签: python linux shell


    【解决方案1】:

    有问题的缓冲主要是脚本方面的问题,而不是 Python 方面的问题;虽然 Python 会缓冲读取,但它不会阻塞,除非缓冲区被清空并且没有可读取的内容。

    确实,您需要在脚本本身中禁用缓冲。添加stdbuf -oL(或-o0,表示完全无缓冲,但行缓冲应该覆盖你,因为你也逐行阅读)在某些情况下(程序不会在内部调整自己的缓冲)会有所帮助。

    如果您仅通过查看 Python 的输出看到此行为,请注意 Python 本身也可以缓冲输出。您可以通过在运行 Python 时传递 -u 来禁用此功能,或者在运行之前设置环境变量 PYTHONUNBUFFERED=1,或者在脚本中,您可以在任何写入后手动调用 sys.stdout.flush()(直接或通过 print 隐式调用) ) 到标准输出。在现代 Python 上,print 接受一个参数以在打印后强制使用 flush,但由于您使用的是 Python 2.x,所以这不是一个选项。

    【讨论】:

    • 感谢@shadowranger 的帮助,让我试试。
    • 那太糟糕了..当我将命令设置为stdbuf -o0 sh abc.sh时,输出仍然被缓冲。不确定问题出在哪里。
    • @Tom:stdbuf 是否有效取决于实际运行的程序;如果他们在运行时在内部调整自己的缓冲,则 stdbuf 的更改将被撤消。如果他们不使用标准流,这些更改根本不会影响他们的 I/O。 stdbuf 手册页对此有注释,提到 teeddcat 是特定的违规者,但这些只是有限的示例。
    • 感谢@hadowranger,当我直接运行python(调用shell)时,它会实时输出,但是当我在我们的调度程序系统中运行它时,输出会被缓冲,我会进行更多调查以了解如何使其发挥作用。
    • 当我在交互模式下运行python时,缓冲区被禁用,但是当我在非交互模式下运行python时,缓冲区没有被禁用,即使我使用过unbuffer sh run.sh a b c,它也不生效。现在不知道如何解决。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 2018-12-12
    相关资源
    最近更新 更多