检测到字符串后退出尾部
Exit tail upon string detection
我正在编写一个屏障来阻止脚本的执行,直到记录了某个关键字。脚本非常简单:
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
还有另一个文件,我知道它更新得非常频繁,但是什么是“干净”的解决方案,以便代码在记录后立即退出 停止?
在bash中,当执行形式为
的命令时
command1 | command2
和 command2
死亡或终止,从 command1
接收 /dev/stdout
的管道被破坏。但是,这不会立即终止 command1
。
所以要实现你想要的是使用进程替换而不是管道
awk '/STOP/{exit}1' < <(tail -f logfile)
当您使用 awk 时,您可以更详细地查看行为:
$ 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
您看到 awk 打印了以下输出:
a # result of print
end # awk test STOP, exits and executes END statement
此外,如果你仔细观察,你会发现 awk 此时已经终止。
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
。
我正在编写一个屏障来阻止脚本的执行,直到记录了某个关键字。脚本非常简单:
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
还有另一个文件,我知道它更新得非常频繁,但是什么是“干净”的解决方案,以便代码在记录后立即退出 停止?
在bash中,当执行形式为
的命令时command1 | command2
和 command2
死亡或终止,从 command1
接收 /dev/stdout
的管道被破坏。但是,这不会立即终止 command1
。
所以要实现你想要的是使用进程替换而不是管道
awk '/STOP/{exit}1' < <(tail -f logfile)
当您使用 awk 时,您可以更详细地查看行为:
$ 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
您看到 awk 打印了以下输出:
a # result of print
end # awk test STOP, exits and executes END statement
此外,如果你仔细观察,你会发现 awk 此时已经终止。
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
。