'grep -q'不使用“tail -f”退出

发布于 2024-12-01 11:33:49 字数 309 浏览 1 评论 0原文

我正在尝试实现一个等待日志文件中特定消息的脚本。记录消息后,我想继续执行脚本。

这是我正在尝试使用 tail -fgrep -q 进行的操作:

# tail -f logfile | grep -q 'Message to continue'

grep 永远不会退出,因此它会永远等待,即使“消息发送到continue' 已记录在文件中。

当我在没有 -f 的情况下运行它时,它似乎工作正常。

I am trying to implement a script that wait for a specific message in a log file. Once the message is logged then I want to continue the script.

Here's what I am trying out with tail -f and grep -q:

# tail -f logfile | grep -q 'Message to continue'

The grep never quit and so it waits forever even if 'Message to continue' is logged in the file.

When I run this without -f it seems to work fine.

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

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

发布评论

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

评论(6

冰之心 2024-12-08 11:33:49

tail -f 将读取文件并显示稍后添加的行,它不会终止(除非发送像 SIGTERM 这样的信号)。 grep 不是这里的阻塞部分,tail -f 是。 grep 将从管道中读取数据,直到它关闭,但它永远不会关闭,因为 tail -f 不会退出并保持管道打开。


您的问题的解决方案可能是(未经测试并且很可能表现不佳):

tail -f logfile | while read line; do
  echo $line | grep -q 'find me to quit' && break;
done

tail -f will read a file and display lines later added, it will not terminate (unless a signal like SIGTERM is sent). grep is not the blocking part here, tail -f is. grep will read from the pipe until it is closed, but it never is because tail -f does not quit and keep the pipe open.


A solution to your problem would probably be (not tested and very likely to perform badly):

tail -f logfile | while read line; do
  echo $line | grep -q 'find me to quit' && break;
done
书间行客 2024-12-08 11:33:49

经过一些实验,我认为问题出在 bash 等待管道中的所有进程以某种形式退出的方式。

使用大约 360 行 C 源代码的纯文件“qqq”(各种程序多次连接),并使用“grep -q return”,然后我观察到:

  1. tail -n 300 qqq | grep -q return 几乎立即退出。
  2. 尾-n 300 -f qqq | grep -q return 不退出。
  3. <代码>tail -n 300 -f qqq | strace -o grep.strace -q return 在中断之前不会退出。 grep.strace 文件结尾为:

    read(0, "#else\n#define _XOPEN_SOURCE 500\n"..., 32768) = 10152
    关闭(1) = 0
    退出组(0)=?
    

    这让我认为 grep 在中断杀死 tail 之前就退出了;如果它正在等待某事,就会显示它收到了信号。

  4. 一个简单的程序,模拟 shell 的功能,但无需等待,表明事情终止。

    <前><代码>#define _XOPEN_SOURCE 600
    #include;
    #include;
    #include;
    #include;
    #include;
    #include;

    静态无效 err_error(const char *fmt, ...)
    {
    int errnum = errno;
    va_list 参数;
    va_start(参数,fmt);
    vfprintf(stderr, fmt, args);
    va_end(参数);
    if (errnum!= 0)
    fprintf(stderr, "%d: %s\n", errnum, strerror(errnum));
    退出(1);
    }

    int 主函数(无效)
    {
    int p[2];
    如果(管道(p)!= 0)
    err_error("创建管道失败\n");
    pid_t 进程号;
    if ((pid = fork()) < 0)
    err_error("分叉失败\n");
    否则如果(pid == 0)
    {
    char *tail[] = { "tail", "-f", "-n", "300", "qqq", 0 };
    dup2(p[1], 1);
    关闭(p[0]);
    关闭(p[1]);
    execvp(尾[0], 尾);
    err_error("执行尾部命令失败");
    }
    别的
    {
    char *grep[] = { "grep", "-q", "return", 0 };
    dup2(p[0], 0);
    关闭(p[0]);
    关闭(p[1]);
    execvp(grep[0], grep);
    err_error("执行 grep 命令失败");
    }
    err_error("这不可能发生!\n");
    返回-1;
    }

    对于固定大小的文件,tail -f 不会退出 - 因此 shell (bash) 似乎会挂起。

  5. 尾-n 300 -f qqq | grep -q return 一直挂着,但是当我使用另一个终端向文件 qqq 添加另外 300 行时,该命令退出了。我将这种情况解释为发生的原因是 grep 已退出,因此当 tail 将新数据写入管道时,它收到 SIGPIPE 并退出,并且 bash > 因此认识到管道中的所有进程都已死亡。

我在 kshbash 中观察到相同的行为。这表明这不是一个错误,而是一些预期的行为。在 x86_64 计算机上的 Linux (RHEL 5) 上进行测试。

After some experimentation, I believe the problem is in the way that bash waits for all the processes in a pipeline to quit, in some shape or form.

With a plain file 'qqq' of some 360 lines of C source (a variety of program concatenated several times over), and using 'grep -q return', then I observe:

  1. tail -n 300 qqq | grep -q return does exit almost at once.
  2. tail -n 300 -f qqq | grep -q return does not exit.
  3. tail -n 300 -f qqq | strace -o grep.strace -q return does not exit until interrupted. The grep.strace file ends with:

    read(0, "#else\n#define _XOPEN_SOURCE 500\n"..., 32768) = 10152
    close(1)                                = 0
    exit_group(0)                           = ?
    

    This is one leads me to think that grep has exited before the interrupt kills tail; if it was waiting for something, there would be an indication that it received a signal.

  4. A simple program that simulates what the shell does, but without the waiting, indicates that things terminate.

    #define _XOPEN_SOURCE 600
    #include <stdlib.h>
    #include <unistd.h>
    #include <stdarg.h>
    #include <errno.h>
    #include <string.h>
    #include <stdio.h>
    
    static void err_error(const char *fmt, ...)
    {
        int errnum = errno;
        va_list args;
        va_start(args, fmt);
        vfprintf(stderr, fmt, args);
        va_end(args);
        if (errnum != 0)
            fprintf(stderr, "%d: %s\n", errnum, strerror(errnum));
        exit(1);
    }
    
    int main(void)
    {
        int p[2];
        if (pipe(p) != 0)
            err_error("Failed to create pipe\n");
        pid_t pid;
        if ((pid = fork()) < 0)
            err_error("Failed to fork\n");
        else if (pid == 0)
        {
            char *tail[] = { "tail", "-f", "-n", "300", "qqq", 0 };
            dup2(p[1], 1);
            close(p[0]);
            close(p[1]);
            execvp(tail[0], tail);
            err_error("Failed to exec tail command");
        }
        else
        {
            char *grep[] = { "grep", "-q", "return", 0 };
            dup2(p[0], 0);
            close(p[0]);
            close(p[1]);
            execvp(grep[0], grep);
            err_error("Failed to exec grep command");
        }
        err_error("This can't happen!\n");
        return -1;
    }
    

    With a fixed size file, tail -f isn't going to exit - so the shell (bash) seems to hang around.

  5. tail -n 300 -f qqq | grep -q return hung around, but when I used another terminal to add another 300 lines to the file qqq, the command exited. I interpret this as happening because grep had exited, so when tail wrote the new data to the pipe, it got a SIGPIPE and exited, and bash therefore recognized that all the processes in the pipeline were dead.

I observed the same behaviour with both ksh and bash. This suggests it is not a bug but some expected behaviour. Testing on Linux (RHEL 5) on an x86_64 machine.

拿命拼未来 2024-12-08 11:33:49
tail -f logfile | grep  --max-count=1  -q 'Message to continue'

诚然,它在读取下一行时退出,而不是立即在匹配的行上退出。

tail -f logfile | grep  --max-count=1  -q 'Message to continue'

Admittedly, it exits when the next line is read, not immediately on the matched one.

Hello爱情风 2024-12-08 11:33:49

我想我应该将此作为答案发布,因为它解释了为什么命令在第二次写入文件后退出:

touch xxx
tail -f xxx | grep -q 'Stop'
ps -ef |grep 'grep -q'
# the grep process is there
echo "Stop" >> xxx
ps -ef|grep 'grep -q'
# the grep process actually DID exit
printf "\n" >> xxx
# the tail process exits, probably because it receives a signal when it 
# tries to write to a closed pipe

I thought I'd post this as an answer since it explains why the command exits after a second write to the file:

touch xxx
tail -f xxx | grep -q 'Stop'
ps -ef |grep 'grep -q'
# the grep process is there
echo "Stop" >> xxx
ps -ef|grep 'grep -q'
# the grep process actually DID exit
printf "\n" >> xxx
# the tail process exits, probably because it receives a signal when it 
# tries to write to a closed pipe
別甾虛僞 2024-12-08 11:33:49

这是因为带有 -f(跟随)选项的 tail 不会退出,而是继续向 grep 提供输出。使用 perl/python 等待日志文件中的行可能会更容易。

使用 Python 子进程模块启动 tail -f。循环读取 tail 的输出,直到看到所需的行,然后退出 Python 脚本。将此解决方案放入您的 shell 脚本中。

Python 脚本将阻止 shell 脚本,直到看到所需的行。

That's because tail with the -f (follow) option doesn't quit, and continues to provide output to grep. Waiting for lines in a log file would probably be easier with perl/python.

Launch tail -f with the Python subprocess module. Read output from tail in a loop until you see the lines you want then exit the Python script. Put this solution inside your shell script.

The Python script will block the shell script until the desired lines are seen.

时光是把杀猪刀 2024-12-08 11:33:49

我正在为我自己的项目寻找这个问题的答案。尝试测试传递的 GPU 何时在 VMware ESXi 虚拟机上变为活动状态。同一问题的多种变体随处可见。这是最近的。我想出了一种方法来欺骗它,如果您可以接受日志中重复的有趣行,那么:

tail -n 1 -f /var/log/vmkernel.log | grep -m 1 IOMMUIntel>>/var/log/
vmkernel.log

这会跟踪日志,一次一行,grep 检查每一行是否第一次出现,并将其附加到日志中,然后 tail 立即退出。

如果您喜欢 VMware passthrough hacking,请在此处阅读更多内容:
http://hackaday.io/project/1071-the-Hydra-multiheaded -虚拟计算机

I was searching for the answer to this for my own project. Trying to test when exactly the passed through GPU becomes active on a VMware ESXi VM. Multiple variations of the same question are everywhere. This one is pretty recent. I figured out a way to fool it, and if you can live with your interesting line repeated in the log then:

tail -n 1 -f /var/log/vmkernel.log | grep -m 1 IOMMUIntel >>/var/log/
vmkernel.log

This tails the log, one line at a time, grep checks each line for first occurrence, and appends it to the log then tail quits immediately.

If you like VMware passthough hacking, read more here:
http://hackaday.io/project/1071-the-hydra-multiheaded-virtual-computer

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文