【问题标题】:Exit tail upon string detection字符串检测时退出尾部
【发布时间】:2019-03-19 16:17:28
【问题描述】:

我正在编写一个障碍来阻止脚本的执行,直到记录了某个关键字。脚本很简单:

tail -F -n0 logfile.log | while read LINE; do
    [[ "$LINE" == *'STOP'* ]] && echo ${LINE} && break;
done

tail -F -n0 logfile.log | grep -m1 STOP

问题是它不会在检测到关键字后立即退出,而是仅在写入下一行之后退出。即:

printf "foo\n"  >> logfile.log  # keeps reading
printf "foo\n"  >> logfile.log  # keeps reading
printf "STOP\n" >> logfile.log  # STOP printed
printf "foo\n"  >> logfile.log  # code exits at last

不幸的是,我不能依赖这样一个事实,即在“STOP”之后将记录另一行(至少不在对我的目的有用的间隔内)。

到目前为止找到的解决方法是tail 也是我知道的另一个文件,我肯定会经常更新,但是什么是“干净”的解决方案,以便代码在记录后立即退出 STOP?

【问题讨论】:

  • 也许写入日志的进程缓冲了它的输出?
  • 也许可以,但是该行会立即打印出来,因此就像卡在echobreak 之间。有了缓冲区,echo 也会被延迟
  • 只有当tail 尝试再次写入管道时,您才会终止,但由于管道已损坏(因为您的while 循环已终止)它会崩溃。它仅在尝试写入时评估pipe 的状况。不要使用管道!

标签: bash pipe sh tail process-substitution


【解决方案1】:

中,执行表单的命令时

command1 | command2

并且command2 死亡或终止,从command1 接收/dev/stdout 的管道损坏。但是,这不会立即终止 command1

所以要实现你想要的就是使用进程替换而不是管道

awk '/STOP/{exit}1' < <(tail -f logfile)

当您使用 时,您可以更详细地查看该行为:

$ touch logfile
$ tail -f logfile | awk '/STOP/{exit}1;END{print "end"}'

这个awk 程序将检查是否看到“STOP”,如果没有则再次打印该行。如果看到“STOP”,它将打印“end”

当你在另一个终端做时

$ echo "a" >> logfile
$ echo "STOP >> logfile
$ echo "b" >> logfile

您会看到 打印以下输出:

a             # result of print
end           # awk test STOP, exits and executes END statement

此外,如果您仔细观察,您会发现 此时已经终止。

ps 在发送“STOP”之前:

13625 pts/39   SN     0:00  |        \_ bash
32151 pts/39   SN+    0:00  |            \_ tail -f foo
32152 pts/39   SN+    0:00  |            \_ awk 1;/STOP/{exit}1;END{print "end"}

ps 发送“STOP”后:

13625 pts/39   SN     0:00  |        \_ bash
32151 pts/39   SN+    0:00  |            \_ tail -f foo

所以 awk 程序终止了,但 tail 没有崩溃,因为它还没有意识到管道已损坏,因为它没有尝试写入它。

当您在终端中使用管道执行以下操作时,您会看到tail 的退出状态:

$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
$ 141 0

这表明 awk 很好地终止了,但 tail 以退出代码 141 终止,这意味着 SIGPIPE

【讨论】:

  • $ 的值?遵循您的建议awk '/STOP/{exit}1' &lt; &lt;(tail -f logfile) 似乎并未反映尾部过程本身的失败。例如,如果日志文件不存在,则 awk 找不到单词 STOP,因此程序成功终止。您在使用管道时讨论了不同的退出代码,但您能否类似地扩展使用命令替换示例时可访问的不同退出代码?
  • 要回复我自己的评论,以及其他有类似疑问的人,一个合理的解决方法是使用awk '/STOP/{exit}1' &lt; &lt;(tail -f logfile || echo "STOP:$?")。这意味着如果 tail 命令失败,awk 进程仍然会找到一个包含 STOP 的字符串,然后您可以使用适当的退出代码退出 awk 来说明 tail 命令本身失败(或添加一些额外的处理来转发精确的从 awk 读取的行中解析的退出代码)
猜你喜欢
  • 2017-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多