`tail -f`, пока текст не виден


20

У меня есть CI-сервер с интерфейсом командной строки, который позволяет мне удаленно запускать задание ( jenkinsCI-сервер и jenkins-cli.jarинструмент).

После того, как я запускаю работу, я веду tail -fжурнал (извините за грязную команду):

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\""

После успешного завершения задания, обычно через 5 минут, я получаю следующую строку:

Finished: SUCCESS

Есть ли хороший способ прекратить бревно на этом этапе? т.е. есть ли tail_until 'some line' my-file.logкоманда?

БОНУС: дополнительный кредит, если вы можете предоставить ответ, который возвращает 0, когда сопоставляется УСПЕХ, 1, когда сопоставляется ОТКАЗ, и ваше решение работает на Mac! (который, я считаю, основан на BSD)

Ответы:


39

Вы можете передать tail -fв sed, сказав, чтобы выйти, когда он видит строку, которую вы ищете:

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

sedвыведет каждую строку, которую обрабатывает по умолчанию, и завершит работу после того, как увидит эту строку. tailПроцесс остановится , когда он пытается записать следующую строку и видит его выходная труба нарушаются


да! идеальный. ... так случайно есть ли способ выйти из 0, если я сопоставляю что-то одно (скажем, «УСПЕХ») и 1, если я сопоставляю что-то другое (например, «НЕИСПРАВНОСТЬ»)?
Aaronstacy

7
@aaronstacy Если вы используете GNU grep, qкоманда принимает необязательный код выхода. Таким образом, sedкоманда будетsed '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Михаил Мрозек

6
Это может не сработать, если Finished: SUCCESSпоследняя строка вывода
lk-

@Michael Mrozek аааа и конечно я не б / у, я использую чертовски mac
aaronstacy

1
Это решение имеет существенный недостаток: в моем случае журнал заканчивается строкой поиска. Больше не будет написано ни одной строки, поэтому процесс останется застрявшим, так как хвост не может сломаться :(
Phate

6
tail -f my-file.log | grep -qx "Finished: SUCCESS"

-q, то есть тихий, выходит, как только находит совпадение

-xделает grepсоответствие всей линии

Для второй части, попробуйте

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

-m <number>говорит grep остановиться после совпадения чисел

и grep -qстатус выхода будет только 0если SUCCESSнайден в конце строки

Если вы хотите увидеть все выходные данные, вы не можете использовать grep -q, но вы все равно можете сделать

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

который делает все, кроме установки состояния выхода на 1, если FAILUREпоявляется.


5
grepПервоначально я использовал в своем ответе, но если он использует, tail -fон, вероятно, хочет увидеть вывод файла; grepне собирается показывать все промежуточные строки
Михаил Мрозек

4

Вариант ответа @ Mikel с комментариями @ Mrozek (я бы ответил на комментарий, но думаю, что у меня пока недостаточно прав)

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

позволит вам использовать решение @ Mikel и по-прежнему видеть вывод на экране


Можем ли мы добавить к этому интервал тайм-аута, например: «если он не читается между 60 и 120 секундами, то прервать хвост и дать код завершения ошибки в оболочке»?
килтек

2

Мне не понравился ни один из ответов, поэтому я решил сделать свой собственный. Этот bash-скрипт отвечает всем критериям и включает БОНУС за выход 1 при ошибке.

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

Также включена функция тайм-аута, которая приведет к коду выхода 3. Если у вас нет команды timeout в вашей системе, возьмите скрипт timeout.sh от Энтони Тиссена:

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

Согласно комментариям ниже, я обновил печать журнала, чтобы остановить расширение escape-символов, и включил все функции стандартного «чтения». См. Https://stackoverflow.com/a/10929511 для полной «прочитанной» информации. Проверка EOF здесь не требуется, но включена для полноты.


Очень хорошо. Подумайте об использовании, while IFS= read -r LOGLINEчтобы не допустить, чтобы оболочка выполняла разбиение пробелов в строках tail.
Ройма

@roaima: readне разделяется, когда есть только одна переменная (и это не массив с -a), но вам нужно, -rесли входные данные содержат обратную косую черту. Но если входные данные содержат обратную косую черту, то echo "$var"могут также испортиться в зависимости от вашей оболочки и / или системы, так что лучшеprintf '%s\n' "$line"
dave_thompson_085


0

Вот скрипт Python, который почти делает то, что я хочу (см. предостережения ниже):

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()

предостережения:

  • строки не печатаются по мере их поступления ... они печатаются группами ... похоже, происходит некоторая буферизация

  • Я должен был бы установить это как скрипт на моем пути или что-то, так что это неудобно, и я бы предпочел гладкую однострочную :)


обновление: tailпохоже, делает ту же самую буферизацию, так что я думаю, что это не то, что стоит пытаться обойти.
Aaronstacy

0

У меня были проблемы с sedи grepи их варианты, поэтому я пишу своиone with bash conditions

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.