我正在尝试实现一个等待日志文件中特定消息的脚本。记录消息后,我想继续脚本。
以下是我使用tail -f
和grep -q
尝试的内容:
# tail -f logfile | grep -q 'Message to continue'
grep
永远不会退出,所以即使文件中记录了“要继续的消息”,它也会永远等待。
当我在没有-f
的情况下运行时,似乎工作正常。
答案 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',然后我观察:
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
不会退出 - 因此shell(bash
)似乎不知所措。
tail -n 300 -f qqq | grep -q return
闲逛,但当我使用另一个终端向文件qqq
添加另外300行时,命令退出。我将此解释为发生因为grep
已退出,因此当tail
将新数据写入管道时,它会获得一个SIGPIPE并退出,因此bash
识别出所有进程管道已经死了。我观察到ksh
和bash
的行为相同。这表明它不是一个错误,而是一些预期的行为。在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