执行 tail -F 直到匹配模式

发布于 2024-10-17 12:58:02 字数 479 浏览 3 评论 0原文

我想对文件执行 tail -F 直到匹配模式。我找到了一种使用 awk 的方法,但恕我直言,我的命令并不是很干净。问题是由于一些限制,我需要只用一行来完成它。

tail -n +0 -F /tmp/foo | \
awk -W interactive '{if ($1 == "EOF") exit; print} END {system("echo EOF >> /tmp/foo")}'

尾部将阻塞,直到文件中出现EOF。它运作得很好。 END 块是强制性的,因为 awk 的 exit 不会立即退出。它使 awk 在退出之前eval END 块。 END 块挂在读取调用上(因为 tail),所以我需要做的最后一件事是在文件中写入另一行以强制 tail 退出。

有人知道更好的方法吗?

I want to do a tail -F on a file until matching a pattern. I found a way using awk, but IMHO my command is not really clean. The problem is that I need to do it in only one line, because of some limitations.

tail -n +0 -F /tmp/foo | \
awk -W interactive '{if ($1 == "EOF") exit; print} END {system("echo EOF >> /tmp/foo")}'

The tail will block until EOF appears in the file. It works pretty well. The END block is mandatory because awk's exit does not exit right away. It makes awk to eval the END block before quitting. The END block hangs on a read call (because of tail), so the last thing I need to do, is to write another line in the file to force tail to exit.

Does someone know a better way to do that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

思念满溢 2024-10-24 12:58:02

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

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

Use tail's --pid option and tail will stop when the shell dies. No need to add extra to the tailed file.

sh -c 'tail -n +0 --pid=$ -f /tmp/foo | { sed "/EOF/ q" && kill $ ;}'
人海汹涌 2024-10-24 12:58:02

试试这个:

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

一旦在 /tmp/foo 中看到“EOF”字符串,整个命令行就会退出。

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

Try this:

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

The whole command-line will exit as soon as the "EOF" string is seen in /tmp/foo.

There is one side-effect: the tail process will be left running (in the background) until anything is written to /tmp/foo.

粉红×色少女 2024-10-24 12:58:02

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

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

存在一些与缓冲区相关的问题,因为如果文件中没有附加更多行,则 sed 将不会读取输入。因此,经过更多研究,我想出了这个:

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

该脚本位于 https://gist.github.com/ 2377029

I've not results with the solution:

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

There is some issue related with the buffer because if there aren't more lines appended to the file, then sed will not read the input. So, with a little more research i came up with this:

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

The script is in https://gist.github.com/2377029

你的呼吸 2024-10-24 12:58:02

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

#!/usr/bin/env tclsh

proc main {filename pattern} {
    set pipe [open "| tail -n +0 -F $filename"]
    set pid [pid $pipe]
    fileevent $pipe readable [list handler $pipe $pattern]
    vwait ::until_found
    catch {exec kill $pid}
}

proc handler {pipe pattern} {
    if {[gets $pipe line] == -1} {
        if {[eof $pipe]} {
            set ::until_found 1
        }
    } else {
        puts $line
        if {[string first $pattern $line] != -1} {
            set ::until_found 1
        }
    }
}

main {*}$argv

那么您将执行 tail_until.tcl /tmp/foo EOF

This is something Tcl is quite good at. If the following is "tail_until.tcl",

#!/usr/bin/env tclsh

proc main {filename pattern} {
    set pipe [open "| tail -n +0 -F $filename"]
    set pid [pid $pipe]
    fileevent $pipe readable [list handler $pipe $pattern]
    vwait ::until_found
    catch {exec kill $pid}
}

proc handler {pipe pattern} {
    if {[gets $pipe line] == -1} {
        if {[eof $pipe]} {
            set ::until_found 1
        }
    } else {
        puts $line
        if {[string first $pattern $line] != -1} {
            set ::until_found 1
        }
    }
}

main {*}$argv

Then you'd do tail_until.tcl /tmp/foo EOF

九歌凝 2024-10-24 12:58:02

这对你有用吗?

tail -n +0 -F /tmp/foo | sed '/EOF/q'

我假设“EOF”是您正在寻找的模式。 sed 命令在找到它时退出,这意味着 tail 应该在下次写入时退出。

我认为,如果在文件末尾附近找到模式,tail 就有可能会徘徊,等待更多输出出现在文件中,而这些输出永远不会出现。如果这确实是一个问题,您可能可以安排杀死它 - 当 sed 终止时,整个管道将终止(除非您使用一个有趣的 shell 认为这不是正确的行为) 。


对 Bash 的抱怨

正如人们担心的那样,bash(至少在 MacOS X 上,但可能到处都是)是一个认为它需要等待 tail 完成的 shell,尽管sed 退出。有时——比我喜欢的更多——我更喜欢旧的 Bourne shell 的行为,它不那么聪明,因此比 Bash 猜错的次数更少。 dribbler 是一个每秒发出一条消息的程序(示例中为“1:Hello”等),并将输出发送到标准输出。在 Bash 中,此命令序列会挂起,直到我在单独的窗口中执行“echo pqr >>/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

遗憾的是,我没有立即看到控制这种行为的选项。我确实找到了 shopt lithist,但这与这个问题无关。

Korn Shell 万岁

我注意到,当我使用 Korn shell 运行该脚本时,它按照我的预期工作 - 留下一个 tail 潜伏在周围,以某种方式被杀死。有效的是 'echo pqr >>> /tmp/foo' 第二个日期命令完成后。

Does this work for you?

tail -n +0 -F /tmp/foo | sed '/EOF/q'

I'm assuming that 'EOF' is the pattern you're looking for. The sed command quits when it finds it, which means that the tail should quit the next time it writes.

I suppose that there is an outside chance that tail would hang around if the pattern is found at about the end of the file, waiting for more output to appear in the file which will never appear. If that's really a concern, you could probably arrange to kill it - the pipeline as a whole will terminate when sed terminates (unless you're using a funny shell that decides that isn't the correct behaviour).


Grump about Bash

As feared, bash (on MacOS X, at least, but probably everywhere) is a shell that thinks it needs to hang around waiting for tail to finish even though sed quit. Sometimes - more often than I like - I prefer the behaviour of good old Bourne shell which wasn't so clever and therefore guessed wrong less often than Bash does. dribbler is a program which dribbles out messages one per second ('1: Hello' etc in the example), with the output going to standard output. In Bash, this command sequence hangs until I did 'echo pqr >>/tmp/foo' in a separate window.

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

Sadly, I don't immediately see an option to control this behaviour. I did find shopt lithist, but that's unrelated to this problem.

Hooray for Korn Shell

I note that when I run that script using Korn shell, it works as I'd expect - leaving a tail lurking around to be killed somehow. What works there is 'echo pqr >> /tmp/foo' after the second date command completes.

半寸时光 2024-10-24 12:58:02

这是 Jon 解决方案的扩展版本,它使用 sed 而不是 grep,以便 tail 的输出发送到 stdout:

sed -r '/EOF/q' <( exec tail -n +0 -f /tmp/foo ); kill $! 2> /dev/null

这有效,因为 sed 在 tail 之前创建,所以 $!保存 tail 的 PID

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

Here's an extended version of Jon's solution which uses sed instead of grep so that the output of tail goes to stdout:

sed -r '/EOF/q' <( exec tail -n +0 -f /tmp/foo ); kill $! 2> /dev/null

This works because sed gets created before tail so $! holds the PID of tail

The main advantage of this over the sh -c solutions is that killing a sh seems to print something to the output such as 'Terminated' which is unwelcome

辞取 2024-10-24 12:58:02
sh -c 'tail -n +0 --pid=$ -f /tmp/foo | { sed "/EOF/ q" && kill $ ;}'

这里的主要问题是 $$
如果按原样运行命令,$$ 不会设置为 sh,而是设置为运行命令的当前 shell 的 PID。

要使 Kill 工作,您需要将 kill $$ 更改为 kill \$$

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

总结一下,以下内容就可以了:

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

您可以选择将 -n 传递给 sed 以保持安静:)

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

Here the main problem is with $$.
If you run command as is, $$ is set not to sh but to the PID of the current shell where command is run.

To make kill work you need to change kill $$ to kill \$$

After that you can safely get rid of --pid=$$ passed to tail command.

Summarising, following will work just fine:

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

Optionally you can pass -n to sed to keep it quiet :)

栀子花开つ 2024-10-24 12:58:02

要杀死悬空 tail 进程,您可以在 (Bash) 进程替换上下文中执行 tail 命令,该命令稍后可以像后台进程一样被杀死。 (代码取自如何通过管道读取“tail -f”中的一行,然后终止?)。

: > /tmp/foo
grep -m 1 EOF <( exec tail -f /tmp/foo ); kill $! 2> /dev/null
echo EOF > /tmp/foo  # terminal window 2

作为替代方案,您可以使用命名管道。

(
: > /tmp/foo
rm -f pidfifo
mkfifo pidfifo
sh -c '(tail -n +0 -f /tmp/foo & echo $! > pidfifo) | 
{ sed "/EOF/ q" && kill $(cat pidfifo) && kill $ ;}'
)

echo EOF > /tmp/foo  # terminal window 2

To kill the dangling tail process as well you may execute the tail command in a (Bash) process substituion context which can later be killed as if it had been a backgrounded process. (Code taken from How to read one line from 'tail -f' through a pipeline, and then terminate?).

: > /tmp/foo
grep -m 1 EOF <( exec tail -f /tmp/foo ); kill $! 2> /dev/null
echo EOF > /tmp/foo  # terminal window 2

As an alternative you could use a named pipe.

(
: > /tmp/foo
rm -f pidfifo
mkfifo pidfifo
sh -c '(tail -n +0 -f /tmp/foo & echo $! > pidfifo) | 
{ sed "/EOF/ q" && kill $(cat pidfifo) && kill $ ;}'
)

echo EOF > /tmp/foo  # terminal window 2
嘿看小鸭子会跑 2024-10-24 12:58:02

准备用于 tomcat =

sh -c 'tail -f --pid=$$ catalina.out | { grep -i -m 1 "服务器启动于" && kill $$ ;}' :

对于上述场景,

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

ready to use for tomcat =

sh -c 'tail -f --pid=$$ catalina.out | { grep -i -m 1 "Server startup in" && kill $$ ;}'

for above scenario :

sh -c 'tail -f   --pid=$ /tmp/foo | { grep -i -m 1 EOF && kill $ ;}'
层林尽染 2024-10-24 12:58:02
tail -f <filename> | grep -q "<pattern>"
tail -f <filename> | grep -q "<pattern>"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文