tail -f и затем выйти при совпадении строки

tail -f и затем выйти при совпадении строки

Я пытаюсь настроить скрипт запуска, который будет запускать tomcat, отслеживать catalina.out на наличие строки "Server startup", а затем запускать другой процесс. Я пробовал различные комбинации tail -f с grep и awk, но пока ничего не работает. Основная проблема, с которой я сталкиваюсь, заключается в принудительном завершении tail после того, как grep или awk сопоставили строку.

Я упростил тестовый пример до следующего.

test.sh is listed below:

#!/bin/sh    
rm -f child.out
./child.sh > child.out &
tail -f child.out | grep -q B

child.sh is listed below:

#!/bin/sh
echo A
sleep 20
echo B
echo C
sleep 40
echo D

Поведение, которое я наблюдаю, заключается в том, что grep завершается через 20 секунд, однако tail потребуется еще 40 секунд, чтобы умереть. Я понимаю, почему это происходит — tail заметит, что канал исчез, только когда он запишет в него, что произойдет только тогда, когда данные будут добавлены в файл. Это усугубляется тем фактом, что tail должен буферизировать данные и выводить символы B и C как одну запись (я подтвердил это с помощью strace). Я пытался исправить это с помощью решений, которые нашел в другом месте, например, с помощью команды unbuffer, но это не помогло.

У кого-нибудь есть идеи, как заставить это работать так, как я ожидаю? Или идеи, как дождаться успешного запуска Tomcat (думаю о том, чтобы дождаться, пока порт TCP узнает, что он запущен, но подозреваю, что это станет сложнее, чем то, что я пытаюсь сделать сейчас). Мне удалось заставить это работать с помощью awk, выполняющего "killall tail" при совпадении, но меня это решение не устраивает. Обратите внимание, что я пытаюсь заставить это работать на RHEL4.

решение1

Что-то вроде этого?

mkfifo child.fifo
tail -f child.out > child.fifo &
pid=$!
grep -q B child.fifo && kill $pid

в полном объеме:

#!/bin/sh    
rm -f child.out
./child.sh > child.out &
mkfifo child.fifo
tail -f child.out > child.fifo &
pid=$!
grep -q B child.fifo && kill $pid
rm child.fifo

Кажется, это занимает 20 секунд.

$ time ./test2.sh

real    0m20.156s
user    0m0.033s
sys     0m0.058s

ОБНОВЛЯТЬ

Кажется, этот способ тоже работает:

#!/bin/sh
rm -f child.out
./child.sh > child.out &
(tail -f child.out | grep -q B child.out)

И если вы видите, что иногда он немедленно завершает работу, попробуйте добавить sleep 1, т.е.

#!/bin/sh
rm -f child.out
./child.sh > child.out &
sleep 1
(tail -f child.out | grep -q B child.out)

решение2

Все в одной строке, замените «do foo» на «command»

# запуск службы tomcat6
# tail -f /var/log/tomcat6/catalina.out | awk '/Запуск сервера/{system("do foo"); выход 0}'

решение3

Отбросьте хвост. Поскольку вы начинаете с пустого child.out, он вам не нужен и (как вы обнаружили) это усложняет ситуацию. Просто выполните grep для первого экземпляра в цикле сна.

until fgrep -q "Server startup" child.out; do sleep 1; done

Если вам действительно нужно сохранить хвост, поскольку вы не всегда начинаете с пустого catalina.out, поместите хвост внутрь цикла:

until tail child.out| fgrep -q "Server startup"; do sleep 1; done

Связанный контент