Linux: блокировать до тех пор, пока строка не будет сопоставлена ​​в файле ( "tail + grep with blocking" )

Есть ли какой-то однострочный способ в bash/GNU-инструментах для блокировки до тех пор, пока в файле не будет сопоставлена ​​строка? В идеале, с тайм-аутом. Я хочу избежать многострочного цикла.

Обновление: Похоже, я должен был подчеркнуть, что я хочу, чтобы процесс завершился, когда строка была сопоставлена.

Ответ 1

Спасибо за ответы, но важная часть заключалась в том, что процесс блокируется до тех пор, пока не будет найден, а затем закончится. Я нашел это:

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

-q не очень портативен, но я буду использовать Red Hat Enterprise Linux, так что все в порядке. И с таймаутом:

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

Ответ 2

Я делаю вариант с sed вместо grep, печатая все анализируемые строки.

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

script находится в https://gist.github.com/2377029

Ответ 3

tail -f file | grep word | head -n1

Будет опубликован snip с асинхронным тайм-аутом

На данный момент: Как включить таймер в Bash Scripting?

Связанный ответ определяет функцию "run_or_timeout", которая делает то, что вы ищете, в режиме bash -savvy

Ответ 4

$ 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

Взгляните на параметр --max-count:

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

Он выйдет после первой строки, соответствующей PATTERN.


EDIT: обратите внимание на комментарий @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

Ответ 6

ждать появления файла

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

Дождитесь появления строки в apper в файле

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

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

Ответ 7

У меня было аналогичное требование и вышло следующее.

Один лайнер, которым вы пользуетесь, - это строка, начинающаяся с "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 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 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 console log file (if applicable)"
        exit 1
    else
        info_msg "Success! Pattern was found."
        exit 0
    fi
fi

Я реализовал это в автономном режиме script, который можно использовать для запуска команды, ожидая, что ее файл журнала будет иметь требуемый шаблон с таймаутом.

Доступно здесь: run_and_wait.sh