避免 bash 脚本中命令组(大括号)的输出缓冲

避免 bash 脚本中命令组(大括号)的输出缓冲

我有一个 bash 脚本,其中包含一组用大括号括起来的命令{ ... }。该组包含一些初始echo命令,然后一圈。在每次迭代时,循环执行各种慢的命令(基本上带有curl一些额外的解析)。每次迭代都很慢(因为网络交互),但它打印一行(Python 代码);据我所知,命令本身不应该出现缓冲问题,因为它们终止工作并离开。

整组命令通过管道传输到python -u(我也尝试过tail -f以进行检查),显然整个循环是在python -uor读取任何内容之前执行的tail -f

我知道如何取消缓冲(如果可能的话)命令与各种工具类似,stdbuf但我认为它在这里没有帮助,因为看起来问题来自命令分组而不是来自这样或那样的命令。

有什么提示吗?

答案1

(未来的读者请注意:这里的愤怒语气不是针对这个问题,而是针对我试图回答这个问题时所犯的错误以及它们所需要的多次编辑。)

噢,出于怜悯。问题出在tail -f.这工作得很好:

#!/bin/bash
printf 'hi\n'
{
    for i in 1 2 3 4; do
        sleep 0.5
        /bin/echo $i
    done;
} | cat
printf 'bye\n'

这不是管道,也不是团体。它是tail。就像追我们自己的尾巴一样!

因此,tail -f失败是因为由于某种原因它没有立即输出。不知道为什么python -u失败,但我不认为这是脚本中的任何内容。也许可以尝试unbuffer一下。cat至少尝试使用您的脚本,并验证在这种情况下它是否未缓冲。


早期失败的尝试故意留在这里,以便未来的读者可以理解这些评论。

该脚本表现出与您遇到的相同类型的缓冲问题:

#!/bin/bash
printf 'hi\n'
{
    for i in 1 2 3 4; do
    sleep 0.5
    printf '%s\n' $i
    done;
} | tail -f
printf 'bye\n'

这个没有。组内的输出被重定向到 stderr,然后来自整个组的 stderr 通过管道传输到命令。由于它是 stderr,因此它是无缓冲的。

#!/bin/bash
printf 'hi\n'
{
    for i in 1 2 3 4; do
    sleep 0.5
    printf '%s\n' $i 1>&2
    done;
} |& tail -f
printf 'bye\n'

改编自王红琴的回答这个问题。困难在于找到一种用大括号而不是显式命令来取消缓冲管道的方法。不得不摆弄一段时间才能使重定向正常工作。

答案2

你只需要做:

{   stdbuf -o0 curl ...
    stdbuf -o0 whatever ...
}|  tail -f

...这适用于动态链接的应用程序,尽管我很确定curl包含它自己的解缓冲某种开关。

相关内容