Bash 一次打印整个文件! (使用 for 循环)

Bash prints whole file in one go! (Using for loop)

我有一个文件,其 data/output 如下所示:

7044 5.2 2:10 7856 4.7 0:27 10819 3.9 0:23 7176 3.3 0:25 7903 2.9 0:30 10850

我正在尝试打印此文件,在暂停 1 秒后逐步打印....但是 bash 正在一次打印整个文件。

来自this的回答 我添加了一行来更改 IFS,此命令给出:

IFS=$' ';for f in "$( cat output.txt )" ; do echo $f;sleep 1;done;

给予

另请注意,awk '{ print ,, }' output.txt 可以正常工作,但 for 循环中的命令无法迭代 根据需要一步步来。

for 循环未按预期工作的另一个示例:

awk '{ print }' output.txt | tail -n2 | head -n1 <---有效

for i in "$( cat output.txt | wc -l )";do awk '{ print }' output.txt | tail -n$i | head -n1; sleep 1; done <---这没有按预期工作。

基本上,在寻找解决方案之前找到并理解真正的问题很重要。 您的问题归结为您想要定期、无缓冲的 shell 数据打印输出。

Shell 缓冲发送到 STDOUT 的数据,因此数据循环的工作方式与您的直觉建议有点不同,并且可能会造成混淆。数据会收集在缓冲区中,直到缓冲区满或程序退出,然后才会有数据刷新。因此,如果数据块较大或接近数据缓冲区的大小,您可能会产生“无缓冲”操作的错误印象。 shell 在交互方式和将数据重定向到文件时的工作方式不同,这可能会造成额外的混淆。请注意,stderr 未缓存。

为了更好地理解,请阅读此 post whosebug.com/a/13933741/282728

我们知道问题出在哪里。如何解决?

解决方案1.最简单的代码总是最好的,我们只需要顺序处理数据行,每行延迟1s发送到STDOUT即可。 AWK 非常适合此类任务。

    awk '{print ; system("sleep 1");}' input.txt

为了便于参考,我将您的文件名从 output.txt 更改为 input.txt

解决方案2.GNU版的GAWK也允许你使用fflush()来刷新缓冲区。如果你有 gawk 版本 5.1 或更低你也可以使用“时间”扩展后跟 gawk sleep() 函数而不是创建子 shell 和系统睡眠。

    gawk '@load "time";  { print ; fflush(); sleep(1); }' input.txt

解决方案 3. 如果由于某种原因我们不能或不想使用 AWK,您可以像这样使用 GNU sed:

    cut -d" " -f 2 input.txt | sed 'e sleep 1'

考虑:

a. 如果问题更复杂并且您没有在管道中使用 dd、cat 和 tee,也许您应该对 GNU coreutils 包中的 stdbuf 感兴趣 https://www.gnu.org/software/coreutils/manual/html_node/stdbuf-invocation.html

    stdbuf -oL [nohup] yourscript

    -o switches to stdout
    -L turn on line buffering

可选的 nohup 防止脚本在例如之后终止。远程连接丢失,如果任务需要很长时间,这会很有用。

b.如果要周期性的将数据传输到结果文件中,那么可以考虑使用脚本程序:

    [nohup] script -q -c yourprogram -f output.txt

    -q mute script, block messages like "done" from being sent to stdout
    -c starts the program instead of the interactive shell

c. 或编写一个小的 C 程序来刷新缓冲区。 这只是一个简单的缓冲区欠载演示,并非完整的解决方案!

    int x=0;
    while(x<10) {
        printf("%d",x);
        fflush(stdout);
        sleep(1);
        x++;
    }

请参阅 stdlib 中的刷新 (stdio.h) https://en.cppreference.com/w/c/io/fflush sleep 属于 POSIX 标准,而不是 C99,因此需要使用 unistd.h 库 https://pubs.opengroup.org/onlinepubs/007908799/xsh/sleep.html

d.其他编程语言自然也有类似的buffer flushing。