我想實現一個等待日誌文件中特定消息的腳本。一旦消息被記錄,然後我想繼續該腳本。'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