在bash / GNU工具中是否有一些单行方式阻止,直到文件中有匹配的字符串?理想情况下,超时。我想避免多行循环。
更新:似乎我应该强调我希望在字符串匹配时结束进程。
答案 0 :(得分:21)
谢谢你们的回答,但重要的是这个过程会阻塞直到找到,然后结束。我发现了这个:
grep -q 'PATTERN' <(tail -f file.log)
-q
不太便携,但我只会使用Red Hat Enterprise Linux,所以没关系。
超时:
timeout 180 grep -q 'PATTERN' <(tail -f file.log)
答案 1 :(得分:6)
我使用sed而不是grep创建一个变体,打印所有解析的行。
sed '/PATTERN/q' <(tail -n 0 -f file.log)
答案 2 :(得分:3)
查看--max-count
选项:
tail -f file.log | grep -m 1 'PATTERN'
它将在匹配PATTERN
的第一行之后退出。
编辑:请注意以下@ Karoly的评论。如果file.log
速度很慢,则grep
进程可能会阻塞,直到在匹配行之后将其他内容添加到文件中。
echo 'context PATTERN line' >> file.log ## grep shows the match but doesn't exit
将打印匹配的行,但在将附加内容附加到文件之前它不会退出(即使它还没有换行符):
echo -n ' ' >> file.log ## Now the grep process exits
在某些情况下(例如高速日志文件),这不是什么大问题,因为无论如何都可能很快将新内容添加到文件中。
另请注意,当从控制台读取stdin时,此行为不会发生,因此grep
从管道中读取的方式似乎有所不同:
$ grep -m1 'PATTERN' - # manually type PATTERN and enter, exits immediately
$ cat | grep -m1 'PATTERN' # manually type PATTERN and enter, and it hangs
答案 3 :(得分:2)
tail -f file | grep word | head -n1
将使用异步超时发布剪辑
目前:How to include a timer in Bash Scripting?
链接的答案定义了一个'run_or_timeout'函数,可以用非常精力充沛的方式完成您正在寻找的内容
答案 4 :(得分:2)
$ tail -f path | sed /pattern/q
或者,如果要抑制不匹配行的输出:
$ tail -f path | sed -n '/pattern/{p; q;}'
添加超时的简单方法是:
$ cmd& sleep 10; kill $! 2> /dev/null
(抑制kill中的错误,以便进程终止时 在时间到期之前,你没有得到“没有这样的过程”警告)。 请注意,这根本不是很强大,因为cmd可能是这样 将终止并且pid计数将包围和其他一些 命令将在计时器到期时具有该pid。
答案 5 :(得分:0)
等待文件出现
while [ ! -f /path/to/the.file ]
do sleep 2; done
等待字符串出现在文件
中while ! grep "the line you're searching for" /path/to/the.file
do sleep 10; done
答案 6 :(得分:0)
我有类似的要求,并提出以下建议。
你所追求的单行是以&#34;超时......开头的行。&#34;其余的代码是为单行提供所需信息以及事后清理所需的准备工作。
##
## Start up the process whose log file we want to monitor for a specific pattern.
##
touch file_to_log_nohup_output.log
nohup "some_command" "some_args" >> file_to_log_nohup_output.log 2>&1 &
my_cmd_pid=$!
## Specify what our required timeout / pattern and log file to monitor is
my_timeout=10m
my_logfile="/path/to/some_command's/log/file.txt"
my_pattern="Started all modules."
## How does this work?
## - In a bash sub shell, started in the background, we sleep for a second and
## then execute tail to monitor the application's log file.
## - Via the arguments passed to it, tail has been configured to exit if the
## process whose log file it is monitoring dies.
## - The above sub shell, is executed within another bash sub shell in which
## we identify the process id of the above sub shell and echo it to stdout.
## - Lastly, in that sub shell we wait for the sub shell with tail running in
## it as a child process, to terminate and if it does terminate, we redirect
## any output from its stderr stream to /dev/null.
## - The stdout output of the above sub shell is piped into another sub shell
## in which we setup a trap to watch for an EXIT event, use head -1 to read
## the process id of the tail sub shell and finally start a grep process
## to grep the stdout for the requested pattern. Grep will quit on the first
## match found. The EXIT trap will kill the process of the tail sub shell
## if the sub shell running grep quits.
##
## All of this is needed to tidy up the monitoring child processes for
## tail'ing + grep'ing the application log file.
##
## Logic of implementing the above sourced from: http://superuser.com/a/1052328
timeout ${my_timeout} bash -c '((sleep 1; exec tail -q -n 0 --pid=$0 -F "$1" 2> /dev/null) & echo $! ; wait $! 2>/dev/null ) | (trap "kill \${my_tail_pid} 2>/dev/null" EXIT; my_tail_pid="`head -1`"; grep -q "$2")' "${my_cmd_pid}" "${my_logfile}" "${my_pattern}" 2>/dev/null &
##
## We trap SIGINT (i.e. when someone presses ctrl+c) to clean up child processes.
##
trap 'echo "Interrupt signal caught. Cleaning up child processes: [${my_timeout_pid} ${my_cmd_pid}]." >> "file_to_log_nohup_output.log"; kill ${my_timeout_pid} ${my_cmd_pid} 2> /dev/null' SIGINT
wait ${my_timeout_pid}
my_retval=$?
trap - SIGINT
## If the time out expires, then 'timeout' will exit with status 124 otherwise
## it exits with the status of the executed command (which is grep in this
## case).
if [ ${my_retval} -eq 124 ]; then
echo "Waited for [${my_timeout}] and the [${my_pattern}] pattern was not encountered in application's log file."
exit 1
else
if [ ${my_retval} -ne 0 ]; then
echo "An issue occurred whilst starting process. Check log files:"
echo " * nohup output log file: [file_to_log_nohup_output.log]"
echo " * application log file: [${my_logfile}]"
echo " * application's console log file (if applicable)"
exit 1
else
info_msg "Success! Pattern was found."
exit 0
fi
fi
我已将上述内容实现为一个独立的脚本,该脚本可用于运行命令,等待其日志文件具有所需的模式,并具有超时。
此处可用:run_and_wait.sh