'grep -q'没有退出'tail -f'

时间:2011-08-24 16:21:31

标签: linux bash grep

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

以下是我使用tail -fgrep -q尝试的内容:

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

grep永远不会退出,所以即使文件中记录了“要继续的消息”,它也会永远等待。

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

6 个答案:

答案 0 :(得分:9)

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

答案 1 :(得分:4)

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

使用大约360行C源的普通文件'qqq'(各种程序连接几次),并使用'grep -q return',然后我观察:

  1. tail -n 300 qqq | grep -q return几乎立即退出。
  2. tail -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
    close(1)                                = 0
    exit_group(0)                           = ?
    

    这是让我认为grep在中断杀死tail之前退出的原因;如果它正在等待某事,则会有迹象表明它收到了信号。

  4. 一个简单的程序,模拟shell的作用,但没有等待,表示事情终止。

    #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;
    }
    

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

  5. tail -n 300 -f qqq | grep -q return闲逛,但当我使用另一个终端向文件qqq添加另外300行时,命令退出。我将此解释为发生因为grep已退出,因此当tail将新数据写入管道时,它会获得一个SIGPIPE并退出,因此bash识别出所有进程管道已经死了。
  6. 我观察到kshbash的行为相同。这表明它不是一个错误,而是一些预期的行为。在x86_64计算机上在Linux(RHEL 5)上进行测试。

答案 2 :(得分:3)

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

不可否认,它会在读取下一行时退出,而不是立即在匹配的行上退出。

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

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

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

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

答案 5 :(得分:0)

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

tail -n 1 -f /var/log/vmkernel.log | grep -m 1 IOMMUIntel&gt;&gt; / var / log / vmkernel.log

这会使日志,一次一行,grep检查第一次出现的每一行,并将其附加到日志然后立即退出尾部。

如果您喜欢VMware passthough hacking,请在此处阅读更多内容: http://hackaday.io/project/1071-the-hydra-multiheaded-virtual-computer