`хвіст -f`, поки не буде видно текст


20

У мене є сервер CI з інтерфейсом командного рядка, який дозволяє мені віддалено розпочати роботу ( jenkinsсервер CI та 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, коли SUCCESS збігається, 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 aaaand звичайно я не b / c я використовую friggin 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не збирається показувати всі проміжні лінії
Michael Mrozek

4

Варіант щодо відповіді @ Mikel з коментарями @ Mrozek (я б відповів на коментар, але, думаю, у мене ще недостатньо привілеїв)

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

дозволить використовувати рішення @ Mikel і все ще побачити вихід на екрані


Чи можемо ми додати до цього інтервал інтервалу тайм-аута, наприклад: "якщо його не читати від 60 до 120 секунд, то перервіть хвіст та введіть код виходу помилки в оболонці"?
kiltek

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.sh від Anthony Thyssen:

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

Відповідно до наведених нижче коментарів, я оновив друк журналу, щоб зупинити розширення розширення символів і включив усі функції стандартного "читання". Дивіться /programming//a/10929511 для отримання повної інформації про "читання". Перевірка EOF тут не потрібна, але включена для повноти.


Дуже хороша. Подумайте про використання, while IFS= read -r LOGLINEщоб запобігти розщепленню пробілів на лініях від tail.
roaima

@roaima: readне ділиться, коли є лише одна змінна (і це не масив з -a), але вам це потрібно, -rякщо вхідні дані містять звороту косу рису . Але якщо вхідні дані містять зворотну косу рису, то вони echo "$var"можуть також printf '%s\n' "$line"
перекручуватися


0

ось сценарій пітона, який майже робить те, що я хочу (див. попередження нижче):

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.