Назад | Перейти на главную страницу

tail -f, а затем выйти по соответствующей строке

Я пытаюсь настроить сценарий запуска, который запускает tomcat, отслеживает в catalina.out строку «Запуск сервера», а затем запускает другой процесс. Я пробовал различные комбинации tail -f с grep и awk, но пока ничего не работает. Основная проблема, с которой я столкнулся, заключается в том, чтобы заставить хвост умирать после того, как 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 секунд, однако хвосту потребуется еще 40 секунд, чтобы умереть. Я понимаю, почему это происходит - tail заметит, что канал пропал, только когда он пишет в него, что происходит только тогда, когда данные добавляются в файл. Это усугубляется тем фактом, что tail должен буферизовать данные и выводить символы B и C как одну запись (я подтвердил это с помощью strace). Я попытался исправить это с помощью решений, которые нашел в другом месте, например, с помощью команды unbuffer, но это не помогло.

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

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

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)

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

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

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

# service tomcat6 start
# tail -f /var/log/tomcat6/catalina.out | awk '/Server startup/{system("do foo"); exit 0}'

Терять хвост. Поскольку вы начинаете с пустого 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