`tail -f` sampai teks terlihat

20

Saya memiliki server CI dengan antarmuka baris perintah yang memungkinkan saya untuk memulai pekerjaan dari jarak jauh ( jenkinsserver CI dan jenkins-cli.jaralatnya).

Setelah saya memulai pekerjaan saya tail -flog (maaf untuk perintah berantakan):

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

Setelah pekerjaan berhasil diselesaikan, biasanya setelah setidaknya 5 menit, saya mendapatkan baris berikut pada output:

Finished: SUCCESS

Apakah ada cara yang baik untuk berhenti mengikuti log pada saat ini? yaitu apakah ada seperti tail_until 'some line' my-file.logperintah?

BONUS: kredit ekstra jika Anda dapat memberikan jawaban yang mengembalikan 0 saat SUKSES dicocokkan, 1 saat FAILURE dicocokkan, dan solusi Anda berfungsi di mac! (yang saya percaya berdasarkan bsd)

aaronstacy
sumber

Jawaban:

39

Anda dapat memasang pipa ke tail -fdalam sed, menyuruhnya untuk berhenti ketika melihat garis yang Anda cari:

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

sedakan menampilkan setiap baris yang diproses secara default, dan keluar setelah melihat garis itu. The tailProses akan berhenti ketika mencoba untuk menulis baris berikutnya dan melihat pipa outputnya rusak

Michael Mrozek
sumber
booh ya! sempurna. ... jadi kebetulan ada cara untuk keluar dari 0 jika saya cocok dengan satu hal (katakan 'SUKSES') dan 1 jika saya cocok dengan sesuatu yang lain (seperti mungkin 'KEGAGALAN')?
aaronstacy
7
@ aaronstacy Jika Anda menggunakan GNU grep, qperintah tersebut mengambil kode keluar opsional. Jadi sedperintahnya adalahsed '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Michael Mrozek
6
Ini mungkin tidak berfungsi jika Finished: SUCCESSmerupakan baris terakhir dari keluaran
lk-
@Michael Mrozek aaaand tentu saja saya tidak b / c saya menggunakan friggin mac
aaronstacy
1
Solusi ini memiliki kelemahan utama: dalam kasus saya log diakhiri oleh baris yang dicari. Tidak akan ada lagi baris yang ditulis sehingga prosesnya akan tetap macet karena ekor tidak memiliki cara untuk memecahkan :(
Phate
6
tail -f my-file.log | grep -qx "Finished: SUCCESS"

-q, Yang berarti tenang, berhenti segera setelah menemukan kecocokan

-xmerek grepmencocokkan seluruh baris

Untuk bagian kedua, cobalah

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

-m <number>memberitahu grep untuk berhenti setelah nomor cocok

dan grep -qstatus keluar hanya akan 0jika SUCCESSditemukan di akhir baris

Jika Anda ingin melihat semua output, Anda tidak dapat menggunakan grep -q, tetapi Anda masih bisa melakukannya

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

yang melakukan segalanya kecuali mengatur status keluar ke 1 jika FAILUREmuncul.

Mikel
sumber
5
grepAwalnya saya menggunakan jawaban saya, tetapi jika dia menggunakan tail -fdia mungkin ingin melihat output file; greptidak akan menampilkan semua garis tengah
Michael Mrozek
4

Variasi pada jawaban @ Mikel dengan komentar @ Mrozek (saya akan menjawab komentar tersebut tetapi saya pikir saya belum memiliki cukup hak istimewa)

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

akan memungkinkan Anda untuk menggunakan solusi @ Mikel dan masih melihat output di layar

Chirlo
sumber
Bisakah kita menambahkan intervensi timeout ke ini, seperti: "jika tidak dibaca antara 60 hingga 120 detik, maka batalkan buntut dan berikan kode keluar kesalahan dalam shell"?
kiltek
2

Saya tidak suka ada jawaban di sini, jadi memutuskan untuk menggulirkan jawaban saya sendiri. Skrip bash ini memenuhi semua kriteria, dan termasuk BONUS untuk keluar dari 1 pada kegagalan.

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

Termasuk juga adalah fitur batas waktu, yang akan menghasilkan kode keluar dari 3. Jika Anda tidak memiliki perintah batas waktu pada sistem Anda, ambil skrip timeout.sh dari Anthony Thyssen:

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

Per komentar di bawah ini, saya memperbarui cetakan log untuk menghentikan ekspansi karakter dan termasuk semua fitur standar 'baca'. Lihat /programming//a/10929511 untuk rincian lengkap 'baca'. Pemeriksaan EOF tidak diperlukan di sini, tetapi sudah termasuk untuk kelengkapan.

verayth
sumber
Sangat bagus. Pertimbangkan menggunakan while IFS= read -r LOGLINEuntuk mencegah shell melakukan pemisahan spasi pada garis tail.
roaima
@roaima: readtidak terpecah ketika hanya ada satu variabel (dan itu bukan array dengan -a), tetapi Anda perlu -rjika data input berisi backslash. Tetapi jika data input mengandung backslash, maka echo "$var"mungkin juga mengacaukan tergantung pada shell dan / atau sistem Anda, jadi lebih baikprintf '%s\n' "$line"
dave_thompson_085
@ dave_thompson_085 Memahami "IFS = read -r line"
roaima
0

inilah skrip python yang hampir melakukan apa yang saya inginkan (lihat peringatan di bawah):

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

peringatan:

  • garis-garis tidak tercetak saat mereka masuk ... mereka dicetak dalam kelompok-kelompok ... sepertinya ada beberapa penyangga yang terjadi

  • saya harus menginstal ini sebagai skrip di jalan saya atau sesuatu, jadi itu tidak nyaman, dan saya lebih suka slick one-liner :)

aaronstacy
sumber
pembaruan: tailtampaknya melakukan buffering yang sama, jadi saya kira itu bukan sesuatu yang layak untuk dicoba.
aaronstacy
0

Saya punya masalah dengan seddan grepdan opsi mereka, jadi saya menulis milik sayaone with bash conditions

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

Anda juga mencoba

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