2011-08-24 57 views
7

我想实现一个等待日志文件中特定消息的脚本。一旦消息被记录,然后我想继续该脚本。'grep -q'不能以'tail -f'退出

这里就是我想出来用tail -fgrep -q

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

grep从没有放弃过,所以它永远等待,即使“消息继续”的文件中被记录下来。

当我运行这个没有-f它似乎工作正常。

+0

它可能以缓冲在尾部发生有关。当我运行你的命令时,它不会退出,但在再次写入文件后退出。 – Kevin

回答

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 
+0

作为一个细节,中断,退出和其他信号也会停止'tail -f'。不过,你的诊断基本上是正确的。 –

+0

@Jonathan:但是在阅读grep的manpage后我感到困惑。 '-q'应该在第一次匹配后立即退出,所以op **的例子应该可以工作。 grep退出并停止从管道读取 – knittl

+0

是的,我也是...我对此感到困惑。这对我来说是一种'新'的行为;我记得'-q'等同于'-s',提前终止是令人惊讶的。我最好的猜测是'grep'通过继续阅读避免发送SIGPIPE到'tail',但我没有证明这一点。 (我要编辑我的评论以删除第二句,但我没有及时赶到那里)。 –

0

这是因为tail-f(后续)选择不退出,并继续将输出提供给grep。使用perl/python可能会更容易等待日志文件中的行。

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

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

0

我想我会张贴此作为一个答案,因为它解释了为什么该命令将退出第二写入到文件后:

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 
+1

事实上,'tail -f'在试图向管道写入新输出时会发送一个'SIGPIPE',此时管道上的读取器已经退出。 'tail -f'的问题是_usually_文件的“尾部”将适合对管道的单个写入,即使读取器只读取第一个字节并退出,'SIGPIPE'也不会被发送,直到随后的写入尝试。 –

3

一些实验后,我相信这个问题是在bash方式以某种形式或形式等待管道中的所有进程退出。

随着C源(各种程序级联几次以上),部分360行普通文件“QQQ”和使用“grep的-q返回”,那么我观察:

  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不会退出 - 这样的外壳(bash)似乎流连。

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

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

+4

不错的分析!有趣的是,'grep -q pattern <(tail -f logfile)'工作得很好。 –

+0

@KolyolyHorvath为什么这还不是答案? –

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

诚然,当读取下一行,不会立即对匹配一个退出。

0

我正在为我自己的项目寻找答案。尝试测试VMware ESXi VM上传递的GPU是否处于活动状态。同一个问题的多种变化无处不在。这是最近的。我想出了一个办法来欺骗它,如果你可以在日志中重复你感兴趣的行,那么:

tail -n 1 -f /var/log/vmkernel.log |的grep -m 1 IOMMUIntel >> /无功/日志/ vmkernel.log

此尾部日志,在每次一行,grep的检查每一行第一次出现,并将其追加到日志然后尾巴立即退出。

如果你像VMware passthough黑客攻击,在这里阅读更多: http://hackaday.io/project/1071-the-hydra-multiheaded-virtual-computer