我正在尝试实现一个脚本,该脚本会等待日志文件中出现特定的消息。一旦消息被记录,那么我就想继续执行脚本。
以下是我正在使用的 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 Leffler-q
选项后,它应该在第一次匹配后立即退出,所以操作示例应该有效。grep会退出并停止从管道中读取。 - knittl-q
相当于 -s
,而早期终止令人惊讶。我最好的猜测是 grep
通过继续读取避免向 tail
发送 SIGPIPE,但我还没有证明。 (我本来要编辑我的评论以删除第二句话,但我来不及了。) - Jonathan Lefflerbash
等待管道中的所有进程退出的方式存在某种问题。使用一个包含大约360行C源代码(多次连接的各种程序)的普通文件“qqq”,并使用“grep -q return”,我观察到:
tail -n 300 qqq | grep -q return
does exit almost at once.tail -n 300 -f qqq | grep -q return
does not exit.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.
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.
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.我发现在使用 ksh
和 bash
时出现了相同的行为。这表明这不是一个错误,而是某种预期的行为。测试环境为Linux(RHEL 5)x86_64机器。
grep -q pattern <(tail -f logfile)
这个命令也能正常工作。 - Karoly Horvathtail -f logfile | grep --max-count=1 -q 'Message to continue'
我觉得我应该把这个作为答案发布,因为它解释了为什么在第二次写入文件后命令会退出:
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
的问题在于,通常文件的“尾部”将适合单个写入管道,即使读取器仅读取第一个字节并退出,也不会发送SIGPIPE
直到尝试进行下一次写入。 - Greg A. Woods这是因为使用带有-f
(跟随)选项的tail
不会退出,并继续向grep
提供输出。使用perl/python等语言等待日志文件中的行可能更容易。
使用Python子进程模块启动tail -f
。在循环中从tail
读取输出,直到看到所需的行,然后退出Python脚本。将此解决方案放入您的shell脚本中。
Python脚本将阻塞shell脚本,直到看到所需的行。
我正在为自己的项目寻找答案。尝试测试在VMware ESXi虚拟机上何时精确地通过GPU。同样的问题有多种变化,到处都是。这个比较新。我想出了一个方法来欺骗它,如果你可以接受在日志中重复你感兴趣的行:
tail -n 1 -f /var/log/vmkernel.log | grep -m 1 IOMMUIntel >>/var/log/ vmkernel.log
这个命令会一次读取一行日志,grep检查每一行是否第一次出现,并将其附加到日志中,然后tail立即退出。
如果你喜欢VMware passthough hacking,请在这里阅读更多信息: http://hackaday.io/project/1071-the-hydra-multiheaded-virtual-computer