วิธีการ 'grep' สตรีมต่อเนื่อง


729

เป็นไปได้ไหมที่จะใช้grepในการสตรีมต่อเนื่อง?

สิ่งที่ฉันหมายถึงคือการเรียงลำดับของtail -f <file>คำสั่ง แต่มีgrepในผลลัพธ์เพื่อเก็บเฉพาะบรรทัดที่ฉันสนใจ

ฉันพยายามแล้วtail -f <file> | grep patternแต่ดูเหมือนว่าgrepจะสามารถดำเนินการได้เมื่อtailเสร็จสิ้นแล้วนั่นคือการพูดที่ไม่เคยทำ


9
มีความเป็นไปได้สูงที่โปรแกรมสร้างไฟล์ไม่ได้ล้างข้อมูลเอาต์พุต
Steve-o

tail -f fileทำงาน (ฉันเห็นผลลัพธ์ใหม่ตามเวลาจริง)
Matthieu Napoli

6
น่าจะเหมาะสมกับunix.stackexchange.com
Luc M

@Luc แน่นอนไม่คิดอย่างนั้น
Matthieu Napoli

อาจไม่มีบรรทัดใหม่ในอินพุตสตรีมของคุณ? หาก grep เป็นเช่นนั้นจะไม่ดำเนินการต่อ
ลินช์

คำตอบ:


1326

เปิดgrepโหมดการบัฟเฟอร์บรรทัดเมื่อใช้ grep BSD (FreeBSD, Mac OS X และอื่น ๆ )

tail -f file | grep --line-buffered my_pattern

คุณไม่จำเป็นต้องทำสิ่งนี้เพื่อ grep GNU (ใช้กับ Linux ใด ๆ ) เนื่องจากจะล้างข้อมูลตามค่าเริ่มต้น (YMMV สำหรับ Unix-like อื่น ๆ เช่น SmartOS, AIX หรือ QNX)


3
@MichaelNiemand คุณสามารถใช้ไฟล์ tail -F | grep --line-buffered my_pattern
jcfrei

47
@MichaelGoldshteyn ใช้ง่าย ผู้คนโหวตขึ้นเพราะพวกเขาพบหน้านี้เมื่อพวกเขา google "grep line buffered" และมันแก้ปัญหาสำหรับพวกเขาซึ่งอาจไม่ตรงกับคำถาม
ฝน

4
ผมมาที่นี่พยายามที่จะ grep straceการส่งออกของ หากไม่มี--line-bufferedมันจะไม่ทำงาน
sjas

5
@MichaelGoldshteyn (และ upvoters ของความคิดเห็นของเขา): ฉันมักจะมีปัญหานี้ด้วยtail -f | grepและ--line-bufferedแก้ปัญหาให้ฉัน (บน Ubuntu 14.04, GNU grep รุ่น 2.16) "การใช้การบัฟเฟอร์บรรทัดอยู่ที่ไหนถ้าตรรกะ stdout เป็น tty" ถูกใช้ ในgit.savannah.gnu.org/cgit/grep.git/tree/src/grep.c , line_bufferedถูกกำหนดโดย parser อาร์กิวเมนต์เท่านั้น
Aasmund Eldhuset

8
@MichaelGoldshteyn ฉันใช้ macOS โดยใช้ BSD grep และไม่--line-bufferedได้รับอะไรเลย อย่างไรก็ตามหลังจากการทดสอบดูเหมือนว่า GNU grep จะทำสิ่งที่คุณอธิบาย เช่นเดียวกับ Unix ทุกอย่างมันขึ้นอยู่กับการใช้งานแพลตฟอร์มของคุณ เนื่องจากคำถามไม่ได้ระบุแพลตฟอร์มข้อมูลของคุณดูเหมือนจะเป็นเท็จ - หลังจากตรวจสอบโค้ดสำหรับ grep BSD และเปรียบเทียบกับ GNU grep พฤติกรรมจึงถูกควบคุมโดยตัวเลือก --line-buffered มันเป็นเพียงแค่ GNU grep flush โดยปริยาย
Richard Waite

118

ฉันใช้tail -f <file> | grep <pattern>ตลอดเวลา

มันจะรอจนกว่า grep flushes ไม่จนกว่าจะเสร็จ (ฉันใช้ Ubuntu)


4
ซึ่งสามารถอยู่ได้ระยะหนึ่งดังนั้นอย่าพยายามใจร้อน
glglgl

ใช้เวลานานเท่าไร
Matthieu Napoli

@ Matthieu: ส่วนใหญ่ขึ้นอยู่กับสิ่งที่คุณ grep สำหรับและขนาดบัฟเฟอร์อยู่บนระบบปฏิบัติการของคุณ หาก grep ตรงกับสตริงสั้น ๆ ทุก ๆ สองสามชั่วโมงมันจะเป็นวันก่อนที่จะล้างข้อมูลครั้งแรก
tripleee

13
ส่วนท้ายไม่ได้ใช้บัฟเฟอร์บัฟเฟอร์ - grep ทำ
XzKto

7
ไม่ได้ grep จะไม่ทำการบัฟเฟอร์ขณะที่เอาต์พุตกำลังไปยังอุปกรณ์ tty เนื่องจากเป็นคำตอบที่ชัดเจน มันจะทำการบัฟเฟอร์บรรทัด! นี่คือคำตอบที่ถูกต้องและควรเป็นคำตอบที่ยอมรับได้ ดูความคิดเห็นของฉันอีกต่อไปเพื่อตอบรับ ( ผิด ) ยอมรับในปัจจุบันสำหรับรายละเอียดเพิ่มเติม
Michael Goldshteyn

67

ฉันคิดว่าปัญหาของคุณคือ grep ใช้บัฟเฟอร์เอาต์พุตบางตัว ลอง

tail -f file | stdbuf -o0 grep my_pattern

มันจะตั้งค่าโหมดบัฟเฟอร์การส่งออกของ grep เพื่อ unbuffered


7
และนี่คือข้อดีที่สามารถใช้สำหรับคำสั่งอื่น ๆ อีกgrepมากมาย
Peter V. Mørch

4
อย่างไรก็ตามในขณะที่ฉันได้ค้นพบหลังจากการเล่นมากขึ้นกับมันคำสั่งบางอย่างเพียงล้างผลผลิตของพวกเขาเมื่อเชื่อมต่อกับ TTY และการที่unbuffer(ในexpect-devแพคเกจในเดเบียน) เป็นพระมหากษัตริย์ ดังนั้นฉันจะใช้ unbuffer กว่า stdbuf
Peter V. Mørch

5
@Peter V. Mørchใช่คุณพูดถูกบางครั้ง unbuffer สามารถทำงานได้ที่ stdbuf ไม่สามารถ แต่ฉันคิดว่าคุณกำลังพยายามค้นหา 'เวทย์มนตร์' ที่มักจะแก้ไขปัญหาของคุณแทนที่จะเข้าใจปัญหาของคุณ การสร้าง tty เสมือนเป็นงานที่ไม่เกี่ยวข้อง Stdbuf ทำสิ่งที่เราต้องการอย่างแน่นอน (ตั้งบัฟเฟอร์เอาท์พุทมาตรฐานให้คุณค่า) ในขณะที่ unbuffer ทำสิ่งที่ซ่อนอยู่มากมายที่เราอาจไม่ต้องการ (เปรียบเทียบการโต้ตอบtopกับ stdbuf และ unbuffer) และไม่มีทางออก 'วิเศษ' จริงๆ: บางครั้ง unbuffer ล้มเหลวเช่นกัน awk ใช้การใช้บัฟเฟอร์ที่แตกต่างกัน (stdbuf จะล้มเหลวด้วย)
XzKto

2
"แต่ฉันคิดว่าคุณกำลังพยายามหาโปรแกรม 'วิเศษ' ที่จะแก้ไขปัญหาของคุณแทนที่จะเข้าใจปัญหาของคุณ" - ฉันคิดว่าคุณพูดถูก! ;-)
Peter V. Mørch

1
ข้อมูลเพิ่มเติมบางอย่างเกี่ยวกับstdbuf`unbuffer และ stdio buffering ที่pixelbeat.org/programming/stdio_buffering
Tor Klingberg

13

หากคุณต้องการค้นหาการแข่งขันในไฟล์ทั้งหมด (ไม่ใช่แค่ท้าย) และคุณต้องการให้มันนั่งรอการแข่งขันใหม่ ๆ ได้ผลดี:

tail -c +0 -f <file> | grep --line-buffered <pattern>

-c +0ธงกล่าวว่าการส่งออกควรจะเริ่มต้น0ไบต์ ( -c) จากจุดเริ่มต้น ( +) ของแฟ้ม


12

ในกรณีส่วนใหญ่คุณสามารถtail -f /var/log/some.log |grep fooและมันจะทำงานได้ดี

หากคุณต้องการใช้หลาย greps ในไฟล์บันทึกการทำงานและคุณพบว่าคุณไม่ได้รับเอาต์พุตคุณอาจต้องติด--line-bufferedสวิตช์ลงในgrep กลางของคุณเช่น:

tail -f /var/log/some.log | grep --line-buffered foo | grep bar

7

คุณอาจพิจารณาคำตอบนี้เป็นการปรับปรุง .. โดยปกติฉันจะใช้

tail -F <fileName> | grep --line-buffered  <pattern> -A 3 -B 5

- F ดีกว่าในกรณีที่หมุนไฟล์ (-f จะทำงานไม่ถูกต้องหากหมุนไฟล์)

-A และ -B มีประโยชน์ในการรับบรรทัดก่อนและหลังการเกิดรูปแบบ .. บล็อกเหล่านี้จะปรากฏขึ้นระหว่างตัวคั่นบรรทัดประ

แต่สำหรับฉันฉันชอบทำสิ่งต่อไปนี้

tail -F <file> | less

สิ่งนี้มีประโยชน์มากหากคุณต้องการค้นหาไฟล์บันทึกในสตรีม ฉันหมายถึงย้อนกลับไปข้างหน้าและมองลึก ๆ


4
grep -C 3 <pattern>, แทนที่ -A <N> และ -B <N> ถ้า N เหมือนกัน
AKS

6

ไม่เห็นใครเสนอข้อเสนอนี้ตามปกติของฉัน:

less +F <file>
ctrl + c
/<search term>
<enter>
shift + f

ฉันชอบสิ่งนี้เพราะคุณสามารถใช้ctrl + cเพื่อหยุดและนำทางผ่านไฟล์เมื่อใดก็ตามที่ต้องการจากนั้นเพียงกดshift + fเพื่อกลับสู่การค้นหาแบบสดและการสตรีม


4

sedจะเป็นตัวเลือกที่ดีกว่า (ตัวแก้ไขสตรีม )

tail -n0 -f <file> | sed -n '/search string/p'

และถ้าคุณต้องการให้คำสั่ง tail ออกเมื่อคุณพบสตริงที่ต้องการ:

tail --pid=$(($BASHPID+1)) -n0 -f <file> | sed -n '/search string/{p; q}'

เห็นได้ชัดว่า bashism: $ BASHPID จะเป็นรหัสกระบวนการของคำสั่ง tail คำสั่ง sed ถัดจากหางในไพพ์ดังนั้น id กระบวนการเซดจะเป็น $ BASHPID + 1


1
การสันนิษฐานว่ากระบวนการถัดไปที่เริ่มต้นในระบบ ( $BASHPID+1) จะเป็นของคุณเป็นเท็จในหลาย ๆ สถานการณ์และไม่ทำอะไรเลยเพื่อแก้ไขปัญหาบัฟเฟอร์ซึ่งอาจเป็นสิ่งที่ OP กำลังพยายามถาม โดยเฉพาะอย่างยิ่งการแนะนำsedมากกว่าgrepที่นี่ดูเหมือนว่าเพียงเรื่องของการ (พิรุธ) การตั้งค่า (คุณสามารถรับp;qพฤติกรรมด้วยgrep -m 1ถ้าเป็นจุดที่คุณกำลังพยายามส่งมอบ)
tripleee

ใช้งานได้คำสั่ง sed พิมพ์แต่ละบรรทัดทันทีที่พร้อมคำสั่ง grep ด้วย--line-bufferedไม่ทำ ฉันจริงใจไม่เข้าใจลบ 1
MUY เบลเยี่ยม

เป็นที่ทราบกันมานานแล้วว่าการบัฟเฟอร์เป็นปัญหากับgrep ไม่มีการดำเนินการพิเศษจะต้องจับเส้นบัฟเฟอร์ใช้sedมันเป็นพฤติกรรมเริ่มต้นจึงเน้นของฉันของคำว่ากระแส และจริงไม่มีการรับประกัน $ BASHPID + 1 จะเป็นpid ที่ถูกต้องที่จะติดตาม แต่เนื่องจากการจัดสรร pid นั้นเป็นลำดับและคำสั่ง piped ได้รับการกำหนดpidทันทีหลังจากนั้นจึงเป็นไปได้มากที่สุด
Christian Herr

1

ใช่มันใช้งานได้จริง Grepและคำสั่ง Unix ส่วนใหญ่ทำงานบนสตรีมทีละหนึ่งบรรทัด แต่ละบรรทัดที่ออกมาจากหางจะถูกวิเคราะห์และส่งต่อหากตรงกับ


2
นั่นไม่ถูกต้องจริง หากgrepเป็นคำสั่งสุดท้ายในห่วงโซ่ท่อมันจะทำหน้าที่ตามที่คุณอธิบาย อย่างไรก็ตามถ้ามันอยู่ตรงกลางมันจะบัฟเฟอร์รอบ ๆ เอาต์พุต 8k ในแต่ละครั้ง
Mahmoud Al-Qudsi

1

คำสั่งนี้ใช้ได้กับฉัน (Suse):

mail-srv:/var/log # tail -f /var/log/mail.info |grep --line-buffered LOGIN  >> logins_to_mail

การรวบรวมการล็อกอินเข้าสู่บริการเมล


-1

คุณจะไม่ประสบความสำเร็จอย่างแน่นอน

tail -f /var/log/foo.log |grep --line-buffered string2search

เมื่อคุณใช้ "colortail" เป็นนามแฝงสำหรับหางเช่น ในทุบตี

alias tail='colortail -n 30'

คุณสามารถตรวจสอบโดยแบ่งตามชนิดนามแฝงว่านี้บางสิ่งบางอย่างเอาท์พุทเช่นนามแฝงหาง isan colortail -n 30ของ ถ้าอย่างนั้นคุณมีผู้ร้าย :)

สารละลาย:

ลบนามแฝงด้วย

unalias tail

ตรวจสอบให้แน่ใจว่าคุณใช้ไบนารีหาง 'ของจริง' โดยคำสั่งนี้

type tail

ซึ่งควรส่งออกสิ่งที่ชอบ:

tail is /usr/bin/tail

จากนั้นคุณสามารถเรียกใช้คำสั่งของคุณ

tail -f foo.log |grep --line-buffered something

โชคดี.


-4

ใช้ awk (ยูทิลิตี้ทุบตีอีกอัน) แทน grep ที่คุณไม่มีตัวเลือกบัฟเฟอร์บรรทัด! มันจะสตรีมข้อมูลของคุณจากหางอย่างต่อเนื่อง

นี่คือวิธีที่คุณใช้ grep

tail -f <file> | grep pattern

นี่คือวิธีที่คุณจะใช้ awk

tail -f <file> | awk '/pattern/{print $0}'

6
สิ่งนี้ไม่ถูกต้อง Awk นอกกรอบทำการบัฟเฟอร์บรรทัดเหมือนกับเครื่องมือ Unix มาตรฐานอื่น ๆ ส่วนใหญ่ (ยิ่งไปกว่านั้น{print $0}คือซ้ำซ้อนเนื่องจากการพิมพ์คือการกระทำเริ่มต้นเมื่อเงื่อนไขผ่านไป)
tripleee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.