Linux:阻塞直到文件中的字符串匹配(“tail + grep with blocks”)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6454915/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 04:41:49  来源:igfitidea点击:

Linux: Block until a string is matched in a file ("tail + grep with blocking")

linuxgrepblockgnu

提问by Ondra ?i?ka

Is there some one-line way in bash/GNU tools to block until there's a string matched in a file? Ideally, with timeout. I want to avoid multi-line loop.

在 bash/GNU 工具中是否有某种单行方式来阻止,直到文件中有匹配的字符串?理想情况下,超时。我想避免多行循环。

Update:Seems like I should have emphasize that I want the process to end when the string is matched.

更新:似乎我应该强调我希望在匹配字符串时结束该过程。

采纳答案by Ondra ?i?ka

Thanks both for answers, but the important part was that the process blocks until found, then ends. I found this:

感谢两位的回答,但重要的部分是进程阻塞直到找到,然后结束。我找到了这个:

grep -q 'PATTERN' <(tail -f file.log)

-qis not much portable, but I will only use Red Hat Enterprise Linux so it's ok. And with timeout:

-q不太便携,但我只会使用 Red Hat Enterprise Linux,所以没关系。并超时:

timeout 180 grep -q 'PATTERN' <(tail -f file.log)

回答by sehe

tail -f file | grep word | head -n1

Will post snip with async timeout

将发布带有异步超时的剪辑

For now: How to include a timer in Bash Scripting?

现在:如何在 Bash 脚本中包含计时器?

The linked answer defines a 'run_or_timeout' function that does what you are looking for in a very bash-savvy way

链接的答案定义了一个“run_or_timeout”函数,它以非常精通 bash 的方式执行您正在寻找的操作

回答by William Pursell

$ tail -f path | sed /pattern/q

or, if you want to suppress the output of non-matching lines:

或者,如果您想抑制不匹配行的输出:

$ tail -f path | sed -n '/pattern/{p; q;}'

A simple-minded way to add a timeout is to do:

添加超时的一种简单方法是:

$ cmd& sleep 10; kill $! 2> /dev/null

(Suppress the errors from the kill so that if the process terminates before the time expires, you don't get the "No such process" warning). Note that this is not at all robust, since it is possible that cmd will terminate and the pid count will wrap around and some other command will have that pid by the time the timer expires.

(抑制来自 kill 的错误,这样如果进程在时间到期之前终止,您就不会收到“没有这样的进程”警告)。请注意,这根本不是健壮的,因为 cmd 可能会终止并且 pid 计数会回绕,并且在计时器到期时其他一些命令将具有该 pid。

回答by Joe

Take a look at the --max-countoption:

看一下--max-count选项:

tail -f file.log | grep -m 1 'PATTERN'

It will exit after the first line that matches PATTERN.

它将在匹配的第一行之后退出PATTERN



EDIT: take note of @Karoly's comment below. If the file.logvelocity is slow, it's possible that the grepprocess will block until additional content is added to the file afterthe matching line.

编辑:请注意下面@Karoly 的评论。如果file.log速度很慢,则grep进程可能会阻塞,直到在匹配行之后向文件添加其他内容。

echo 'context PATTERN line' >> file.log  ## grep shows the match but doesn't exit

will print the matching line, but it will not exit until additional content is appended to the file (even if it doesn't have a newline yet):

将打印匹配的行,但在附加内容附加到文件之前它不会退出(即使它还没有换行符):

echo -n ' ' >> file.log  ## Now the grep process exits

In some cases (such as a high-velocity log file), this isn't a big deal, because new content is probably going to be added to the file soon anyway.

在某些情况下(例如高速日志文件),这没什么大不了的,因为无论如何新内容可能很快就会添加到文件中。

Also note that this behavior does nothappen when reading from a console as stdin, so it appears to be a difference in the way grepreads from a pipe:

另请注意,从控制台作为标准输入读取时不会发生此行为,因此grep从管道读取的方式似乎有所不同:

$ grep -m1 'PATTERN' -      # manually type PATTERN and enter, exits immediately
$ cat | grep -m1 'PATTERN'  # manually type PATTERN and enter, and it hangs

回答by harley

I make a variant with sed instead of grep, printing all lines parsed.

我用 sed 而不是 grep 制作了一个变体,打印了所有解析的行。

sed '/PATTERN/q' <(tail -n 0 -f file.log)

The script is in https://gist.github.com/2377029

该脚本位于https://gist.github.com/2377029

回答by Mykhaylo Adamovych

wait for file to appear

等待文件出现

while [ ! -f /path/to/the.file ] 
do sleep 2; done

wait for string to apper in file

等待字符串到文件中

while ! grep "the line you're searching for" /path/to/the.file  
do sleep 10; done

https://superuser.com/a/743693/129669

https://superuser.com/a/743693/129669

回答by Jinesh Choksi

I had a similar requirement and came up with the following.

我有一个类似的要求,并提出了以下建议。

The one-liner you are after is the line which starts with "timeout ...." and the rest of the code is the prep work needed to provide the one-liner with the information it will need and to clean up afterwards.

您所追求的单行是以“timeout ....”开头的行,其余代码是为单行提供所需信息并随后进行清理所需的准备工作。

##
## 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=##代码## -F "" 2> /dev/null) & echo $! ; wait $! 2>/dev/null ) | (trap "kill ${my_tail_pid} 2>/dev/null" EXIT; my_tail_pid="`head -1`"; grep -q "")' "${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

I've implemented the above into a stand alone script which can be used to run a command wait for its log file to have the required pattern, with a timeout.

我已经将上述内容实现到一个独立的脚本中,该脚本可用于运行命令等待其日志文件具有所需的模式,并带有超时。

Available here: run_and_wait.sh

可在此处获得:run_and_wait.sh