Я знаю, что этот вопрос задавали много раз, но поверьте мне, я пробовал много предложений. Я пытаюсь сделать постоянно контролировать файл журнала сервера Tomcat, чтобы обнаружить его запуск. Он основан на этом столбик
Я немного изменил его, чтобы добавить таймаут, чтобы он никогда не ждал, если строка вообще отсутствует в файле. Код выглядит так, как показано ниже.
echo 0 > flag
timeout $DEPLOY_WAIT tail -n0 -F $TOMCAT_LOG | while read LOGLINE
do
[[ "${LOGLINE}" == *"INFO: Server startup in"* ]] && echo 1 > flag && pkill -P $$ timeout
done
x=$(cat flag)
if [ $x -ne 0 ];then
Здесь вы можете видеть, что я пишу в файл флага, чтобы определить, истекло ли время ожидания хвоста или он нашел соответствующую строку в файле. Если я изменю его на переменную вроде
flag=0
timeout $DEPLOY_WAIT tail -n0 -F $TOMCAT_LOG | while read LOGLINE
do
[[ "${LOGLINE}" == *"INFO: Server startup in"* ]] && flag=1 && pkill -P $$ timeout
done
if [ $flag -ne 0];then
тогда флаг переменной всегда имеет значение 0. Обновление, выполненное в цикле while, теряется. Я провел небольшое исследование и выяснил, что это связано с тем, что канал заставляет bash порождать новую подоболочку, а параметр передается от родителя к потомку, а не наоборот. Решение, предложенное этим сообщение было переписать вещь без использования труб, таких как
flag=0
while read LOGLINE;
do
[[ "${LOGLINE}" == *"INFO: Server startup in"* ]] && flag=1 && pkill -P $$ timeout
done <<< $(timeout $DEPLOY_WAIT tail -n0 -F $TOMCAT_LOG)
if [ $flag -ne 0];then
Проблема с этим решением заключается в том, что данные передаются в цикл while только после завершения тайм-аута команды [и код для обнаружения процесса тайм-аута и его уничтожения также изменяется. Но это не имеет значения, поэтому не включено], и я не могу обнаружить строку, как только она попадает в файл. Скрипт ждет время тайм-аута, несмотря ни на что. Я ищу способ объединить их в одно элегантное решение, не используя файлы в качестве флага.
Проблема с решением, которое вы пробовали:
done <<< $(timeout $DEPLOY_WAIT tail -n0 -F $TOMCAT_LOG)
заключается в том, что вы захватываете весь вывод команды timeout ...
с помощью $( )
в виде строки (что означает, что должен ожидает завершения процесса), а затем передаете это в цикл как строку здесь (с <<<
). Чтобы цикл обрабатывал вывод по мере его создания, вам нужно имитировать канал, например:
done < <(timeout $DEPLOY_WAIT tail -n0 -F $TOMCAT_LOG)
Это похоже на то, но совсем другое в деталях. Часть <( )
называется подстановкой процесса - она запускает команду timeout ...
как подпроцесс и эффективно вставляет имя файла именованного канала, подключенного к stdout этого процесса. Затем полученная часть < pipename
выполняет чтение цикла из этого именованного канала. Эффект почти такой же, как у обычного канала (как и в вашей первой попытке), за исключением того, что цикл не помещается в подоболочку.
это сработало для меня, но мне пришлось немного изменить сценарий, чтобы найти и остановить процесс тайм-аута. Раньше у процесса тайм-аута был родительский процесс у самого процесса сценария оболочки. После этого изменения создается новый процесс, аналогичный исходному scirpt оболочки, и время ожидания выполняется как дочерний для этого процесса. поэтому для его обнаружения пришлось использовать следующую команду. depoy.sh - это имя скрипта. pkill -P `pgrep -P $$ deploy` тайм-аут
Используйте PIPESTATUS, чтобы проверить, был ли достигнут тайм-аут. В случае тайм-аута возвращаемое значение - 124.
$ timeout 1 sleep 2 | read
Terminated
$ echo $PIPESTATUS
124
$ timeout 2 sleep 1 | read
$ echo $PIPESTATUS
0
И не убивайте timeout
. Он прекращает свое существование, если ребенок умирает.
Вы усложняете себе жизнь. Найдите
inotifywait
в StackOverflow. Вы можете использовать его для отслеживания изменений в журнале и делать все, что вам нужно, при изменении журнала. (обратите внимание на варианты-m
и-e
)