Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Shell 做一个尾部-F直到匹配一个图案_Shell_Sed_Awk_Tcl_Tail - Fatal编程技术网

Shell 做一个尾部-F直到匹配一个图案

Shell 做一个尾部-F直到匹配一个图案,shell,sed,awk,tcl,tail,Shell,Sed,Awk,Tcl,Tail,我想在一个文件上做一个tail-F,直到匹配一个模式。我找到了一种使用awk的方法,但是我的命令不是很干净。问题是,由于一些限制,我只需要在一行中完成 tail -n +0 -F /tmp/foo | \ awk -W interactive '{if ($1 == "EOF") exit; print} END {system("echo EOF >> /tmp/foo")}' 尾部将阻塞,直到文件中出现EOF。它工作得很好。结束块是强制性的,因为awk的“退出”不会立即退出。它

我想在一个文件上做一个tail-F,直到匹配一个模式。我找到了一种使用awk的方法,但是我的命令不是很干净。问题是,由于一些限制,我只需要在一行中完成

tail -n +0 -F /tmp/foo | \
awk -W interactive '{if ($1 == "EOF") exit; print} END {system("echo EOF >> /tmp/foo")}'
尾部将阻塞,直到文件中出现EOF。它工作得很好。结束块是强制性的,因为awk的“退出”不会立即退出。它使awk在退出前评估结束块。END块挂起一个read调用(因为tail),所以我需要做的最后一件事是在文件中写入另一行以强制tail退出


有人知道更好的方法吗?

这对你有用吗

tail -n +0 -F /tmp/foo | sed '/EOF/q'
我假设“EOF”就是你要找的模式。
sed
命令在找到它时退出,这意味着
tail
应该在下次写入时退出

我认为,如果在文件的末尾找到模式,则
tail
很可能会挂起,等待文件中出现更多永远不会出现的输出。如果这确实是一个问题,您可能会安排终止它-管道作为一个整体将在
sed
终止时终止(除非您使用的是一个有趣的shell决定这不是正确的行为)


怒气冲冲 令人担忧的是,
bash
(至少在MacOS X上,但可能无处不在)是一个shell,它认为需要等待
tail
完成,即使
sed
退出。有时——比我喜欢的更多——我更喜欢善良的老伯恩·谢尔的行为,他不那么聪明,因此猜错的次数比巴什少
dribbler
是一个每秒滴出一条消息的程序(示例中为“1:Hello”等),输出为标准输出。在Bash中,这个命令序列一直挂起,直到我在一个单独的窗口中执行了“
echopqr>/tmp/foo

date
{ timeout -t 2m dribbler -t -m Hello; echo EOF; } >/tmp/foo &
echo Hi
sleep 1   # Ensure /tmp/foo is created
tail -n +0 -F /tmp/foo | sed '/EOF/q'
date
遗憾的是,我没有立即看到控制这种行为的选项。我确实找到了
shoptlithist
,但这与这个问题无关

光辉壳牌万岁
我注意到,当我使用KornShell运行该脚本时,它的工作方式与我预期的一样-留下一个
尾巴
潜伏在周围,以某种方式被杀死。在第二个date命令完成后,“
echo pqr>>/tmp/foo
”。

这是Tcl非常擅长的。如果以下为“tail_until.tcl”

然后,您将执行
tail\u直到.tcl/tmp/foo EOF

尝试以下操作:

sh -c 'tail -n +0 -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
只要在/tmp/foo中看到“EOF”字符串,整个命令行就会退出

有一个副作用:tail进程将一直运行(在后台),直到有任何内容写入/tmp/foo。

使用tail的--pid选项,当shell死亡时tail将停止。无需向尾部文件添加额外内容

sh -c 'tail -n +0 --pid=$$ -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
这里的主要问题是
$$
。 如果按原样运行命令,
$$
不会设置为sh,而是设置为运行命令的当前shell的PID

要使kill有效,您需要将
kill$$
更改为
kill\$$

之后,您可以安全地摆脱传递给tail命令的
--pid=$$

总而言之,以下几点很好:

/bin/sh -c 'tail -n 0 -f /tmp/foo | { sed "/EOF/ q" && kill \$$ ;}

(可选)您可以将
-n
传递到
sed
以保持其安静:)

要杀死悬挂的
tail
进程,您也可以在(Bash)进程替换上下文中执行
tail
命令,该替换上下文可以在以后像杀死后台进程一样被杀死。(代码取自)


下面是Jon解决方案的扩展版本,它使用sed而不是grep,这样tail的输出就转到stdout:

sed -r '/EOF/q' <( exec tail -n +0 -f /tmp/foo ); kill $! 2> /dev/null
sed-r'/EOF/q'/dev/null
这是因为sed是在tail so$之前创建的!保持尾巴的PID


与sh-c解决方案相比,这种方法的主要优点是,杀死一个sh似乎会在输出中打印一些不受欢迎的内容,例如“终止”

我没有得到解决方案的结果:

sh -c 'tail -n +0 -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
缓冲区存在一些问题,因为如果没有更多的行附加到文件中,那么sed将不会读取输入。因此,通过进一步研究,我得出了以下结论:

sed '/EOF/q' <(tail -n 0 -f /tmp/foo)
sed'/EOF/q'
tail-f | grep-q“

准备好用于tomcat=

sh-c'tail-f--pid=$$catalina.out{grep-i-m1“服务器启动在”&&kill$$}”

对于上述场景:

sh -c 'tail -f   --pid=$$ /tmp/foo | { grep -i -m 1 EOF && kill $$ ;}'

好极了,不过我必须把它作为一行保存。@shad:没有额外文件的一行吗?:-(我真的很喜欢你的详细解释。你的第一个命令可能是最好的,除了sed的行为与我没有指定结束块时的awk相同。所以我想我暂时保留我的awk命令。只是为了解释一下:“sh-c”用于将管道运行到子shell中,并且能够检索子shell PID。the“$$”行的末尾将扩展到此子shell的PID。我的sed脚本应执行与awk脚本相同的操作(即,显示它看到的所有内容,并在遇到字符串“EOF”时退出)。一旦sed找到“EOF”字符串,“kill”将终止子shell。“tail”悬空进程将保留,因为它将在/tmp/foo上循环部件已退出。请参阅@GregBarrett的答案,了解悬垂尾巴进程的修复方法。很好的改进!这应该是可接受的答案。有什么方法可以摆脱至少在我使用脚本时出现的
7616终止的sh-c…
行?如果您的尾巴不支持
--pid
选项,您可以使用
sh-I-c'tail-n+0-f/tmp/foo{sed”/EOF/q“&&kill 0;}”
.sh-i创建一个新的进程组,并
kill 0
杀死当前进程组中的所有进程。注意:这在BusyBox中不起作用,因此在Alpine上不起作用。您也可以找到正确的答案
sed -r '/EOF/q' <( exec tail -n +0 -f /tmp/foo ); kill $! 2> /dev/null
sh -c 'tail -n +0 -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'
sed '/EOF/q' <(tail -n 0 -f /tmp/foo)
tail -f <filename> | grep -q "<pattern>"
sh -c 'tail -f   --pid=$$ /tmp/foo | { grep -i -m 1 EOF && kill $$ ;}'