bash 'grep -q' 不以 'tail -f' 退出
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7178888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
'grep -q' not exiting with 'tail -f'
提问by AvadhP
I am trying to implement a script that wait for a specific message in a log file. Once the message is logged then I want to continue the script.
我正在尝试实现一个脚本来等待日志文件中的特定消息。记录消息后,我想继续编写脚本。
Here's what I am trying out with tail -fand grep -q:
这是我正在尝试的tail -f和grep -q:
# tail -f logfile | grep -q 'Message to continue'
The grepnever quit and so it waits forever even if 'Message to continue' is logged in the file.
在grep从没有放弃过,所以它永远等待,即使“消息继续”被记录在文件中。
When I run this without -fit seems to work fine.
当我在没有-f它的情况下运行它时,它似乎工作正常。
回答by knittl
tail -fwill read a file and display lines later added, it will not terminate (unless a signal like SIGTERMis sent). grepis not the blocking part here, tail -fis. grepwill read from the pipe until it is closed, but it never is because tail -fdoes not quit and keep the pipe open.
tail -f将读取文件并显示稍后添加的行,它不会终止(除非发送类似信号SIGTERM)。grep不是这里的阻塞部分,tail -f是。grep将从管道中读取直到它关闭,但它永远不会因为tail -f不退出并保持管道打开。
A solution to your problem would probably be (not tested and very likely to perform badly):
您的问题的解决方案可能是(未经测试并且很可能表现不佳):
tail -f logfile | while read line; do
echo $line | grep -q 'find me to quit' && break;
done
回答by Jonathan Leffler
After some experimentation, I believe the problem is in the way that bashwaits for all the processes in a pipeline to quit, in some shape or form.
经过一些实验,我认为问题在于bash等待管道中的所有进程以某种形式退出的方式。
With a plain file 'qqq' of some 360 lines of C source (a variety of program concatenated several times over), and using 'grep -q return', then I observe:
使用大约 360 行 C 源代码的纯文件“qqq”(多次连接的各种程序),并使用“grep -q return”,然后我观察到:
tail -n 300 qqq | grep -q returndoes exit almost at once.tail -n 300 -f qqq | grep -q returndoes not exit.tail -n 300 -f qqq | strace -o grep.strace -q returndoes not exit until interrupted. Thegrep.stracefile 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
grephas exited before the interrupt killstail; 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 -fisn't going to exit - so the shell (bash) seems to hang around.tail -n 300 -f qqq | grep -q returnhung around, but when I used another terminal to add another 300 lines to the fileqqq, the command exited. I interpret this as happening becausegrephad exited, so whentailwrote the new data to the pipe, it got a SIGPIPE and exited, andbashtherefore recognized that all the processes in the pipeline were dead.
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徘徊,但是当我使用另一个终端向文件添加另外 300 行时qqq,命令退出。我将这解释为发生了,因为grep已经退出,所以当tail将新数据写入管道时,它得到一个 SIGPIPE 并退出,bash因此认识到管道中的所有进程都已死。
I observed the same behaviour with both kshand bash. This suggests it is not a bug but some expected behaviour. Testing on Linux (RHEL 5) on an x86_64 machine.
我观察到与ksh和相同的行为bash。这表明它不是错误,而是一些预期的行为。在 x86_64 机器上的 Linux (RHEL 5) 上进行测试。
回答by mmaruska
tail -f logfile | grep --max-count=1 -q 'Message to continue'
Admittedly, it exits when the next line is read, not immediately on the matched one.
诚然,它在下一行被读取时退出,而不是在匹配的一行上立即退出。
回答by Kevin
I thought I'd post this as an answer since it explains why the command exits after a second write to the file:
我想我会将此作为答案发布,因为它解释了为什么命令在第二次写入文件后退出:
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
回答by silverjam
That's because tailwith the -f(follow) option doesn't quit, and continues to provide output to grep. Waiting for lines in a log file would probably be easier with perl/python.
这是因为tail与-f(后续)选择不退出,并继续提供输出grep。使用 perl/python 可能更容易等待日志文件中的行。
Launch tail -fwith the Python subprocess module. Read output from tailin a loop until you see the lines you want then exit the Python script. Put this solution inside your shell script.
tail -f使用 Python 子进程模块启动。从tail循环中读取输出,直到看到所需的行,然后退出 Python 脚本。将此解决方案放入您的 shell 脚本中。
The Python script will block the shell script until the desired lines are seen.
Python 脚本将阻止 shell 脚本,直到看到所需的行。
回答by Eric Mockler
I was searching for the answer to this for my own project. Trying to test when exactly the passed through GPU becomes active on a VMware ESXi VM. Multiple variations of the same question are everywhere. This one is pretty recent. I figured out a way to fool it, and if you can live with your interesting line repeated in the log then:
我正在为我自己的项目寻找答案。尝试测试通过的 GPU 在 VMware ESXi 虚拟机上何时处于活动状态。同一问题的多种变体无处不在。这个是最近的。我想出了一种方法来愚弄它,如果你能忍受在日志中重复你有趣的行,那么:
tail -n 1 -f /var/log/vmkernel.log | grep -m 1 IOMMUIntel >>/var/log/ vmkernel.log
tail -n 1 -f /var/log/vmkernel.log | grep -m 1 IOMMUIntel >>/var/log/vmkernel.log
This tails the log, one line at a time, grep checks each line for first occurrence, and appends it to the log then tail quits immediately.
这会跟踪日志,一次一行,grep 检查每一行是否第一次出现,并将其附加到日志中,然后 tail 立即退出。
If you like VMware passthough hacking, read more here: http://hackaday.io/project/1071-the-hydra-multiheaded-virtual-computer
如果您喜欢 VMware passthrough hacking,请在此处阅读更多信息:http://hackaday.io/project/1071-the-hydra-multiheaded-virtual-computer

