在 Bash 中,管道tail -f
到read
循环会无限期阻塞。
while read LINE0
do
echo "${LINE0}";
done < <( tail -n 3 -f /tmp/file0.txt | grep '.*' )
# hangs
删除-f
or | grep '.*'
,则循环将迭代。
下面的做法是不是悬挂。
tail -n 3 -f /tmp/file0.txt | grep '.*'
是什么导致了这种行为?
Bash 中是否可以跟踪文件并读取管道表达式?
答案1
在管道中,grep
的输出被缓冲。通过 GNU 实现grep
,您可以使用--line-buffered
(文档在这里);例如:
tail -n 3 -f /tmp/file0.txt | grep --line-buffered '.*' |
while IFS= read -r LINE0
do
printf '%s\n' "${LINE0}"
done
答案2
Greg's Wiki 有一篇关于缓冲的综合文章:https://mywiki.wooledge.org/BashFAQ/009
对我有用的技术(Popos 20.04、Ubuntu 20.04)用于stdbuf
进行行缓冲。他们的例子:
tail -f logfile | stdbuf -oL grep 'foo bar' | awk ...
我的用例:
journalctl --output=json -t poke-stats -f |\
stdbuf -oL jq -r '.__REALTIME_TIMESTAMP' |\
stdbuf -oL awk '{print $1-last;last=$1}'