tail -f e então saia na string correspondente

tail -f e então saia na string correspondente

Estou tentando configurar um script de inicialização que inicializará o Tomcat, monitorará o catalina.out para a string "Inicialização do servidor" e, em seguida, executará outro processo. Tenho tentado várias combinações de tail -f com grep e awk, mas ainda não consegui nada. O principal problema que estou tendo parece ser forçar a morte da cauda depois que grep ou awk corresponderem à string.

Simplifiquei para o seguinte caso de teste.

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

O comportamento que estou vendo é que o grep sai após 20 segundos, porém o tail levará mais 40 segundos para morrer. Eu entendo por que isso está acontecendo - tail só notará que o pipe desapareceu quando ele grava nele, o que só acontece quando os dados são anexados ao arquivo. Isso é agravado pelo fato de que tail deve armazenar os dados em buffer e gerar os caracteres B e C como uma única gravação (confirmei isso por strace). Tentei consertar isso com soluções que encontrei em outro lugar, como usar o comando unbuffer, mas isso não ajudou.

Alguém tem alguma idéia de como fazer isso funcionar como eu espero? Ou ideias para aguardar o início bem-sucedido do Tomcat (pensando em esperar que uma porta TCP saiba que ela foi iniciada, mas suspeito que isso se tornará mais complexo do que o que estou tentando fazer agora). Consegui fazê-lo funcionar com o awk fazendo um "killall tail" na partida, mas não estou feliz com essa solução. Observe que estou tentando fazer isso funcionar no RHEL4.

Responder1

Algo assim?

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

na íntegra:

#!/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

Parece funcionar em 20 segundos.

$ time ./test2.sh

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

ATUALIZAR

Desta forma parece funcionar também:

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

E se às vezes você vê que ele sai imediatamente, tente adicionar um sleep 1, ou seja

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

Responder2

Tudo em uma linha, substitua 'do foo' por comando'

# serviço Tomcat6 iniciar
# tail -f /var/log/tomcat6/catalina.out | awk '/Inicialização do servidor/{system("do foo"); saída 0}'

Responder3

Perder o rabo. Como você começa com um child.out vazio, você não precisa dele e (como descobriu) isso complica as coisas. Apenas grep para a primeira instância em um loop de suspensão.

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

Se você precisar manter a cauda porque nem sempre começa com um catalina.out vazio, coloque a cauda dentro do laço:

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

informação relacionada