`tail -f` cho đến khi văn bản được nhìn thấy


20

Tôi đã có một máy chủ CI với giao diện dòng lệnh cho phép tôi khởi động công việc từ xa ( jenkinsmáy chủ CI và jenkins-cli.jarcông cụ).

Sau khi tôi bắt đầu công việc, tôi tail -fđăng nhập (xin lỗi vì lệnh lộn xộn):

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

Sau khi hoàn thành công việc, thường sau ít nhất 5 phút, tôi nhận được dòng sau trên đầu ra:

Finished: SUCCESS

Có một cách tốt để ngừng theo dõi nhật ký tại thời điểm này? tức là có giống như một tail_until 'some line' my-file.loglệnh?

THƯỞNG: tín dụng bổ sung nếu bạn có thể cung cấp câu trả lời trả về 0 khi SUCCESS được khớp, 1 khi FAILURE được khớp và giải pháp của bạn hoạt động trên mac! (mà tôi tin là dựa trên bsd)

Câu trả lời:


39

Bạn có thể dẫn tail -fvào sed, yêu cầu thoát ra khi thấy dòng bạn đang tìm kiếm:

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

sedsẽ xuất ra từng dòng mà nó xử lý theo mặc định và thoát sau khi thấy dòng đó. Các tailquá trình sẽ dừng lại khi nó cố gắng để viết dòng tiếp theo và thấy ống đầu ra của nó được chia


ồ ồ! hoàn hảo. ... Vì vậy, bằng mọi cách có cách nào để thoát 0 nếu tôi khớp một thứ (nói 'THÀNH CÔNG') và 1 nếu tôi khớp với thứ khác (như có thể là 'FAILURE')?
aaronstacy

7
@aaronstacy Nếu bạn đang sử dụng GNU grep, qlệnh sẽ lấy mã thoát tùy chọn. Vì vậy, sedlệnh sẽ làsed '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Michael Mrozek

6
Điều này có thể không hoạt động nếu Finished: SUCCESSlà dòng đầu ra cuối cùng
lk-

@Michael Mrozek aaaand tất nhiên tôi không sử dụng friggin mac
aaronstacy

1
Giải pháp này có một lỗ hổng lớn: trong trường hợp của tôi, nhật ký kết thúc bằng dòng tìm kiếm. Sẽ không có thêm dòng nào được viết nên quá trình sẽ bị kẹt vì đuôi không có cách nào để phá vỡ :(
Phate

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

-q, có nghĩa là yên tĩnh, thoát ra ngay khi nó tìm thấy một trận đấu

-xlàm cho grepphù hợp với toàn bộ dòng

Đối với phần thứ hai, hãy thử

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

-m <number>nói với grep dừng lại sau khi khớp số

grep -qtrạng thái thoát sẽ chỉ được 0nếu SUCCESSđược tìm thấy ở cuối dòng

Nếu bạn muốn xem tất cả đầu ra, bạn không thể sử dụng grep -q, nhưng bạn vẫn có thể làm

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

thực hiện mọi thứ ngoại trừ đặt trạng thái thoát thành 1 nếu FAILURExuất hiện.


5
Tôi đã sử dụng greptrong câu trả lời của mình ban đầu, nhưng nếu anh ta sử dụng tail -fanh ta có thể muốn xem kết quả đầu ra của tập tin; grepsẽ không hiển thị tất cả các dòng trung gian
Michael Mrozek

4

Một biến thể về câu trả lời của @ Mikel với ý kiến ​​của @ Mrozek (Tôi sẽ trả lời về nhận xét nhưng tôi nghĩ tôi chưa có đủ đặc quyền)

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

sẽ cho phép bạn sử dụng giải pháp của @ Mikel và vẫn thấy đầu ra trên màn hình


Chúng ta có thể thêm một khoảng thời gian chờ vào điều này không, như: "nếu nó không được đọc trong khoảng từ 60 đến 120 giây, sau đó hủy bỏ đuôi và đưa ra mã thoát lỗi trong trình bao"?
kiltek 15/03/18

2

Tôi không thích bất kỳ câu trả lời nào ở đây, vì vậy quyết định tự mình thực hiện. Tập lệnh bash này đáp ứng tất cả các tiêu chí và bao gồm TIỀN THƯỞNG để thoát 1 khi không thành công.

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

Ngoài ra, còn có một tính năng hết thời gian chờ, sẽ dẫn đến mã thoát là 3. Nếu bạn không có lệnh hết thời gian trên hệ thống của mình, hãy lấy tập lệnh timeout.sh từ Anthony Thyssen:

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

Theo các bình luận bên dưới, tôi đã cập nhật bản in nhật ký để ngăn chặn việc mở rộng ký tự và bao gồm tất cả các tính năng của một 'đọc' tiêu chuẩn. Xem /programming//a/10929511 để biết chi tiết 'đọc'. Kiểm tra EOF không bắt buộc ở đây, nhưng được bao gồm để hoàn thiện.


Rất đẹp. Xem xét sử dụng while IFS= read -r LOGLINEđể ngăn vỏ thực hiện phân tách khoảng trắng trên các dòng từ tail.
roaima

@roaima: readkhông phân chia khi chỉ có một biến (và đó không phải là một mảng với -a), nhưng bạn cần -rnếu dữ liệu đầu vào chứa dấu gạch chéo ngược. Nhưng nếu dữ liệu đầu vào chứa dấu gạch chéo ngược, thì echo "$var"cũng có thể làm hỏng tùy thuộc vào hệ vỏ và / hoặc hệ thống của bạn, vì vậy tốt hơnprintf '%s\n' "$line"
dave_thedom_085


0

đây là một kịch bản python gần như làm những gì tôi muốn (xem phần bên dưới):

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

hãy cẩn thận

  • các dòng không được in khi chúng đến ... chúng được in theo nhóm ... dường như là một số bộ đệm đang diễn ra

  • Tôi sẽ phải cài đặt tập lệnh này như một tập lệnh trên đường dẫn của tôi hoặc một cái gì đó, vì vậy nó bất tiện, và tôi thích một lớp lót trơn tru hơn :)


cập nhật: taildường như thực hiện cùng một bộ đệm, vì vậy tôi đoán đó không phải là thứ đáng để thử.
aaronstacy

0

Tôi có vấn đề với sedgrepcác lựa chọn của họ, vì vậy tôi viếtone with bash conditions

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.