如何使任何Shell命令的输出无缓冲?

98

有没有一种方法可以在没有输出缓冲的情况下运行shell命令?

例如,hexdump file | ./my_script 将只会以缓冲块的方式将输入从 hexdump 传递给 my_script,而不是每行一次。

实际上,我想知道如何使任何命令成为非缓冲的通用解决方案?


3
更多赞同的问题 http://unix.stackexchange.com/questions/25372 - Trevor Boyd Smith
也许还可以参考 https://dev59.com/TGw05IYBdhLWcg3wkirX - tripleee
5个回答

174

尝试使用stdbuf,它包含在GNU coreutils中,因此几乎可以在任何Linux发行版中找到。这将输入、输出和错误的缓冲区长度都设置为零:

stdbuf -i0 -o0 -e0 command

9
这对我来说比“unbuffer”更有效。 “stdbuf”将我发送给它的任何信号(在我的情况下为“SIGUSR2”)传递给了“command”(这正是我想要发生的),而“unbuffer”似乎不愿意这样做。 - ElDog
7
stdbuf 使用之前提到的 LD_PRELOAD 技巧来实现此功能,因此无法与静态链接或 setuid 可执行文件一起使用。请参阅此问题进行讨论:https://dev59.com/RGvXa4cB1Zd3GeqPJ4NB#18624182 - Nordic Mainframe
11
我发现这非常有用,但它的功能受限,因为它不能隐式地运行脚本。但是,stdbuf -o0 bash 可以运行完整的会话,并且所有我的脚本和别名都可用,并且所有命令都没有输出缓冲,这正是我想要的。当退出这个 bash 实例时,缓冲区当然会恢复。我正在使用 Ubuntu 16.04。 - AFH
2
我非常喜欢这个,所以我把它放在了我的.bash_profile文件的第一行。if [[ "$0" == "-bash" ]]; then exec /usr/bin/stdbuf -i0 -oL -eL /bin/bash -l; fi - IcarusNM
2
在我的工作中,这个exec模式对我很有用,可以将输出发送到日志文件,并且所有的输出行都是缓冲的,而不是完全禁用缓冲:exec > >(stdbuf -i0 -oL -eL awk '{print strftime("%Y-%m-%d %H:%M:%S"), $0 }' | stdbuf -i0 -oL -eL tee "$LOGFILE") 2>&1 - JinnKo
显示剩余2条评论

37

3
似乎unbuffer将命令的stdout和stderr合并了起来...(!) - olejorgenb
3
@olejorgenb 是的,它合并了标准输出和标准错误输出,这是有意设计的:unbuffer 使用 expect,而 expect 的作用是模拟人类在与程序交互时的行为,人类无法区分输出是标准输出还是标准错误输出。 - toolforger

25
据我所知,你不能在没有丑陋的黑科技的情况下做到这一点。写入管道(或从管道读取)会自动开启完全缓冲区,你无法对此做任何事情 :-(。"行缓冲"(这就是你想要的)仅在读取/写入终端时使用。这些丑陋的黑科技正是为此而生:它们将一个程序连接到伪终端上,以便管道中的其他工具以行缓冲模式读/写该终端。整个问题在这里描述:该页面还提供了一些建议(即前面提到的 "丑陋的黑科技"),例如使用unbuffer或使用LD_PRELOAD进行一些技巧操作。

谢谢。我以前从未听说过伪终端。 - bodacydo

23

你也可以使用 script 命令使得 hexdump 的输出按行缓冲(hexdump 将在一个伪终端上运行,这会欺骗 hexdump 认为其将 stdout 写入终端,而不是管道)。

# cf. http://unix.stackexchange.com/questions/25372/turn-off-buffering-in-pipe/
stty -echo -onlcr
script -q /dev/null hexdump file | ./my_script         # FreeBSD, Mac OS X
script -q -c "hexdump file" /dev/null | ./my_script    # Linux
stty echo onlcr

我使用了“-f”参数来刷新,不确定是否必要,但它起作用了。 - Gringo Suave
在我的情况下,stdbuf 失败了,但脚本运行得非常好。当输出被管道传输到 tee 时,该程序会缓冲输出,但在终端中运行时不会。所以,脚本可以正常工作!谢谢! - TerrenceSun
�常��的解决方案,而且它有效��谢谢。😄 - xmnboy
只有一个问题:根据此处引用的scriptman页面,“某些交互式命令(如vi(1))会在typescript文件中创建垃圾。Script最适合不操作屏幕的命令,其结果旨在模拟硬拷贝终端。” - RandomDSdevel

2
应该使用grep或egrep的“--line-buffered”选项来解决这个问题,不需要其他工具。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接