`หาง -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 เมื่อจับคู่ความสำเร็จได้ 1 เมื่อจับคู่ FAILURE ได้และโซลูชันของคุณทำงานบน mac! (ซึ่งฉันเชื่อว่าเป็น bsd ตาม)

คำตอบ:


39

คุณสามารถไพพ์tail -fเข้าไปได้sedโดยบอกให้เลิกเมื่อเห็นบรรทัดที่คุณค้นหา:

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

sedจะส่งออกแต่ละบรรทัดที่ประมวลผลตามค่าเริ่มต้นและออกหลังจากที่เห็นบรรทัดนั้น tailกระบวนการจะหยุดเมื่อพยายามที่จะเขียนบรรทัดถัดไปและเห็นท่อส่งออกของเสีย


เฮ้! สมบูรณ์ ... ดังนั้นโดยโอกาสใด ๆ มีวิธีการออกจาก 0 ถ้าฉันตรงกับสิ่งหนึ่ง (พูดว่า 'ความสำเร็จ') และ 1 ถ้าฉันตรงกับสิ่งอื่น (เช่นอาจจะเป็น 'ล้มเหลว')?
aaronstacy

7
@aaronstacy หากคุณใช้ grep ของ GNU qคำสั่งนั้นจะใช้รหัสทางออกเสริม ดังนั้นsedคำสั่งจะเป็นsed '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Michael Mrozek

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 และยังคงเห็นผลลัพธ์บนหน้าจอ


เราสามารถเพิ่มการหมดเวลา intervall นี้เช่น: "ถ้ามันไม่ได้อ่านระหว่าง 60 ถึง 120 วินาทีแล้วยกเลิกหางและให้รหัสข้อผิดพลาดออกในเปลือก"?
kiltek

2

ฉันไม่ชอบคำตอบใด ๆ ที่นี่ดังนั้นตัดสินใจที่จะม้วนตัวเอง สคริปต์ทุบตีนี้ตรงตามเกณฑ์ทั้งหมดและรวมถึงโบนัสสำหรับการออกจาก 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"
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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.