我想实现一个等待日志文件中特定消息的脚本。一旦消息被记录,然后我想继续该脚本。'grep -q'不能以'tail -f'退出
这里就是我想出来用tail -f
和grep -q
:
# tail -f logfile | grep -q 'Message to continue'
的grep
从没有放弃过,所以它永远等待,即使“消息继续”的文件中被记录下来。
当我运行这个没有-f
它似乎工作正常。
我想实现一个等待日志文件中特定消息的脚本。一旦消息被记录,然后我想继续该脚本。'grep -q'不能以'tail -f'退出
这里就是我想出来用tail -f
和grep -q
:
# tail -f logfile | grep -q 'Message to continue'
的grep
从没有放弃过,所以它永远等待,即使“消息继续”的文件中被记录下来。
当我运行这个没有-f
它似乎工作正常。
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'。不过,你的诊断基本上是正确的。 –
@Jonathan:但是在阅读grep的manpage后我感到困惑。 '-q'应该在第一次匹配后立即退出,所以op **的例子应该可以工作。 grep退出并停止从管道读取 – knittl
是的,我也是...我对此感到困惑。这对我来说是一种'新'的行为;我记得'-q'等同于'-s',提前终止是令人惊讶的。我最好的猜测是'grep'通过继续阅读避免发送SIGPIPE到'tail',但我没有证明这一点。 (我要编辑我的评论以删除第二句,但我没有及时赶到那里)。 –
这是因为tail
与-f
(后续)选择不退出,并继续将输出提供给grep
。使用perl/python可能会更容易等待日志文件中的行。
使用Python子流程模块启动tail -f
。从循环中读取tail
的输出,直到看到所需的行,然后退出Python脚本。把这个解决方案放在你的shell脚本中。
Python脚本将阻止shell脚本,直到看到所需的行。
我想我会张贴此作为一个答案,因为它解释了为什么该命令将退出第二写入到文件后:
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
事实上,'tail -f'在试图向管道写入新输出时会发送一个'SIGPIPE',此时管道上的读取器已经退出。 'tail -f'的问题是_usually_文件的“尾部”将适合对管道的单个写入,即使读取器只读取第一个字节并退出,'SIGPIPE'也不会被发送,直到随后的写入尝试。 –
一些实验后,我相信这个问题是在bash
方式以某种形式或形式等待管道中的所有进程退出。
随着C源(各种程序级联几次以上),部分360行普通文件“QQQ”和使用“grep的-q返回”,那么我观察:
tail -n 300 qqq | grep -q return
确实几乎立即退出。tail -n 300 -f qqq | grep -q return
不退出。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
前;如果它正在等待某件事,就会有迹象表明它收到了信号。
一个简单的程序,模拟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
)似乎流连。
tail -n 300 -f qqq | grep -q return
挂着,但是当我用另一个终端向文件qqq
添加另外300行时,该命令退出。我解释这是因为grep
已退出,所以当tail
将新数据写入管道时,它得到SIGPIPE并退出,因此bash
认识到管道中的所有进程都已死亡。我观察到同样的行为与ksh
和bash
。这表明这不是一个错误,而是一些预期的行为。在x86_64机器上的Linux(RHEL 5)上进行测试。
不错的分析!有趣的是,'grep -q pattern <(tail -f logfile)'工作得很好。 –
@KolyolyHorvath为什么这还不是答案? –
tail -f logfile | grep --max-count=1 -q 'Message to continue'
诚然,当读取下一行,不会立即对匹配一个退出。
我正在为我自己的项目寻找答案。尝试测试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
它可能以缓冲在尾部发生有关。当我运行你的命令时,它不会退出,但在再次写入文件后退出。 – Kevin