`tail -f` até o texto ser visto

20

Eu tenho um servidor de IC com uma interface de linha de comando que permite iniciar remotamente um trabalho ( jenkinsservidor de CI e a jenkins-cli.jarferramenta).

Depois de iniciar o trabalho tail -fno log (desculpe pelo comando confuso):

ssh -t my-jenkins-host.com "tail -f \"/var/lib/jenkins/jobs/$job_name/builds/\`ls -ltr /var/lib/jenkins/jobs/$job_name/builds/ | grep '^l' | tail -n 1|awk '{print \$9}'\`/log\""

Depois que o trabalho é concluído com êxito, geralmente após pelo menos 5 minutos, recebo a seguinte linha na saída:

Finished: SUCCESS

Existe uma boa maneira de parar de seguir o log neste momento? ou seja, existe como um tail_until 'some line' my-file.logcomando?

BÔNUS: crédito extra, se você puder fornecer uma resposta que retorne 0 quando o SUCESSO corresponder, 1 quando o FAILURE corresponder e sua solução funcionar no mac! (que eu acredito que é baseado em bsd)

aaronstacy
fonte

Respostas:

39

Você pode canalizar tail -fpara dentro sed, dizendo para sair quando vir a linha que você está procurando:

tail -f /path/to/file.log | sed '/^Finished: SUCCESS$/ q'

sedproduzirá cada linha processada por padrão e sairá depois de ver essa linha. O tailprocesso será interrompido quando tentar escrever a próxima linha e perceber que seu tubo de saída está quebrado

Michael Mrozek
fonte
booh sim! perfeito. ... então, por acaso, existe uma maneira de sair de 0 se eu corresponder a uma coisa (digamos 'SUCESSO') e 1 se eu corresponder a outra coisa (como talvez 'FAILURE')?
precisa saber é o seguinte
7
@aaronstacy Se você estiver usando o GNU grep, o qcomando usará um código de saída opcional. Então o sedcomando seriased '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Michael Mrozek
6
Isso pode não funcionar se Finished: SUCCESSfor a última linha de saída
lk-
@ Michael Mrozek Aaaand Claro que eu não sou b / c eu estou usando friggin mac
aaronstacy
11
Essa solução tem uma falha importante: no meu caso, o log termina na linha pesquisada. Não há mais linhas serão escritas para que o processo iria ficar preso como cauda tem nenhuma maneira de quebrar :(
Phate
6
tail -f my-file.log | grep -qx "Finished: SUCCESS"

-q, ou seja, silencioso, sai assim que encontra uma correspondência

-xfaz grepcorresponder a linha inteira

Para a segunda parte, tente

tail -f my-file.log | grep -m 1 "^Finished: " | grep -q "SUCCESS$"

-m <number>diz ao grep para parar após a correspondência de números

e o grep -qstatus de saída será apenas 0se SUCCESSfor encontrado no final da linha

Se você deseja ver toda a saída, não pode usar grep -q, mas ainda pode fazer

tail -f my-file.log | grep -m 1 "^Finished: "

que faz tudo, exceto define o status de saída para 1 se FAILUREaparecer.

Mikel
fonte
5
Eu usei grepna minha resposta originalmente, mas se ele estiver usando, tail -fele provavelmente quer ver a saída do arquivo; grepnão mostrará todas as linhas intermediárias #
Michael Mrozek
4

Uma variação da resposta de @ Mikel nos comentários de @ Mrozek (eu teria respondido no comentário, mas acho que ainda não tenho privilégios suficientes)

tail -f my-file.log | tee >( grep -qx "Finished: SUCCESS" )

permitiria que você usasse a solução do @ Mikel e ainda visse a saída na tela

Chirlo
fonte
Podemos adicionar um intervalo de tempo limite a isso, como: "se não for lido entre 60 a 120 segundos, aborte a cauda e forneça um código de saída de erro no shell"?
#
2

Eu não gostei de nenhuma das respostas aqui, então decidi rolar as minhas. Esse script bash atende a todos os critérios e inclui o BÔNUS para a saída 1 em caso de falha.

#!/bin/bash
while IFS= read -r LOGLINE || [[ -n "$LOGLINE" ]]; do
    printf '%s\n' "$LOGLINE"
    [[ "${LOGLINE}" == "Finished: SUCCESS" ]] && exit 0
    [[ "${LOGLINE}" == "Finished: FAILURE" ]] && exit 1
done < <(timeout 300 tail -f my-file.log)
exit 3

Também está incluído um recurso de tempo limite, que resultará em um código de saída 3. Se você não tiver o comando timeout no sistema, pegue o script timeout.sh de Anthony Thyssen:

http://www.ict.griffith.edu.au/anthony/software/timeout.sh

Pelos comentários abaixo, atualizei a impressão do log para interromper a expansão de caracteres de escape e incluí todos os recursos de uma 'leitura' padrão. Consulte /programming//a/10929511 para obter detalhes completos de 'leitura'. A verificação EOF não é necessária aqui, mas está incluída para garantir a integridade.

verayth
fonte
Muito agradável. Considere usar while IFS= read -r LOGLINEpara impedir que o shell execute a divisão de espaço em branco nas linhas tail.
roaima 21/09/19
@roaima: readnão se divide quando há apenas uma variável (e não é uma matriz com -a), mas você precisa -rse os dados de entrada contiverem barra invertida. Mas, se os dados de entrada contém barra invertida, então echo "$var"também pode estragar dependendo da sua concha e / ou sistema, então é melhorprintf '%s\n' "$line"
dave_thompson_085
@ dave_thompson_085 Entendendo "IFS = linha read -r"
roaima 22/09/18
0

aqui está um script python que quase faz o que eu quero (veja advertências abaixo):

import sys,re

def main():
    re_end = re.compile(sys.argv[1])
    re_fail = re.compile(sys.argv[2]) if len(sys.argv) > 2 else None
    for line in sys.stdin:
        sys.stdout.write(line)
        if re_end.match(line):
            sys.exit(0)
        elif re_fail and re_fail.match(line):
            sys.exit(1)

if __name__ == '__main__': main()

ressalvas:

  • as linhas não são impressas quando entram ... elas são impressas em grupos ... parece haver algum buffer acontecendo

  • eu teria que instalar isso como um script no meu caminho ou algo assim, por isso é inconveniente, e eu preferiria uma linha única :)

aaronstacy
fonte
update: tailparece fazer o mesmo buffer, então acho que não vale a pena tentar contornar isso.
precisa saber é o seguinte
0

Eu tive problemas com sede grepe suas opções, então escrevo o meuone with bash conditions

tail -f screenlog.* | 
while IFS= read line; 
 do 
   echo $line; 
   if [[ $line == *Started\ Application* ]]; 
    then pkill tail; 
   fi; 
done
panser
fonte
-1

Você também tenta

 grep -q 'App Started' <(tail -f /var/log/app/app.log)
Deano
fonte