ทำไม“ tail -f … | หาง” ล้มเหลวในการผลิตผลลัพธ์ใด ๆ


36

เหตุใดคำสั่งต่อไปนี้จึงไม่สร้างเอาต์พุตใด ๆ

$ tail -f /etc/passwd | tail

หลังจากอ่านเกี่ยวกับบัฟเฟอร์ฉันได้ลองทำสิ่งต่อไปนี้เพื่อประโยชน์:

$ tail -f /etc/passwd | stdbuf -oL tail

โปรดทราบว่าต่อไปนี้จะสร้างผลลัพธ์:

$ tail /etc/passwd | tail

ดังนั้นสิ่งนี้:

$ tail -f /etc/passwd | head

ฉันใช้ tail version 8.21 (coreutils GNU)


17
ตัวเลข 10 ตัวสุดท้ายของπคืออะไร
Keith Thompson

คำตอบ:


15

ฉันคิดว่าฉันเห็นทุกอย่างใน UNIX คำถามนี้ตบฉันจากความสบายใจของฉัน เป็นคำถามที่ยอดเยี่ยมมาก!

tailแสดงบรรทัด X สุดท้าย tail -fทำสิ่งเดียวกัน แต่โดยพื้นฐานแล้วในวงวนไม่สิ้นสุด: เมื่อเริ่มต้นให้แสดงบรรทัด X สุดท้ายของไฟล์จากนั้นใช้เวทมนต์ OS (เช่น inotify) ตรวจสอบและแสดงบรรทัดใหม่

ในการทำงานของมันtailจะต้องสามารถค้นหาจุดสิ้นสุดของไฟล์ได้ หากtailไม่พบจุดสิ้นสุดของไฟล์มันจะไม่สามารถแสดงบรรทัด X สุดท้ายได้เพราะ "สุดท้าย" ไม่ได้ถูกกำหนด แล้วtailในกรณีนี้จะทำอย่างไร? มันจะรอจนกว่าจะหาจุดสิ้นสุดของไฟล์

พิจารณาสิ่งนี้:

$ chatter() { while :; do date; sleep 1; done; }
$ chatter | tail -f

สิ่งนี้ไม่เคยปรากฏว่ามีความคืบหน้าเนื่องจากไม่มีจุดสิ้นสุดไฟล์ที่chatterแน่นอน

คุณได้รับพฤติกรรมเดียวกันถ้าคุณขอtailให้คุณบรรทัดสุดท้ายจากไปป์ระบบไฟล์ พิจารณา:

$ mkfifo test.pipe
$ tail test.pipe

stdbufการหลีกเลี่ยงปัญหาที่รับรู้นั้นเป็นความพยายามอันสูงส่ง ความจริงที่สำคัญคือการบัฟเฟอร์ I / O ไม่ใช่สาเหตุที่แท้จริง: การไม่มีจุดสิ้นสุดไฟล์ที่แน่นอนคือ หากคุณตรวจสอบซอร์สโค้ด tail.cคุณจะเห็นfile_linesความคิดเห็นของฟังก์ชันอ่าน:

END_POS เป็นไฟล์ออฟเซ็ตของ EOF (ใหญ่กว่าออฟเซ็ตหนึ่งไบต์สุดท้าย)

และนั่นคือเวทมนตร์ คุณต้องมีไฟล์สิ้นสุดเพื่อให้หางทำงานในการกำหนดค่าใด ๆ headไม่มีข้อ จำกัด นั้นเพียงแค่ต้องการเริ่มต้นไฟล์ (ซึ่งอาจไม่มีลองhead test.pipe) สตรีมเครื่องมือที่มุ่งเน้นเช่นsedและawkไม่จำเป็นต้องมีจุดเริ่มต้นหรือจุดสิ้นสุดของไฟล์: มันทำงานบนบัฟเฟอร์


37

tail -fหางของจริง ๆ แล้วเป็นสิ่งที่ไม่รู้จักในปัจจุบันดังนั้นคนอื่นควรtailรู้ได้อย่างไร ในทางกลับกันtail -fบางสิ่งก็เป็นที่รู้จักกันดีและสามารถนำไปผ่านกระบวนการได้

หรือเพื่อทำให้ง่ายขึ้น: tailสัมพันธ์กับจุดสิ้นสุดของไฟล์ แต่เอาต์พุตสตรีมของtail -fไม่มี EOF (อย่างน้อยไม่ก่อนที่จะสิ้นสุด)

หากคุณพบครั้งแรกtailของ pid และฆ่ามันคุณควรแล้วเห็นผลลัพธ์จากสอง


21

คำตอบทางเทคนิค

เมื่อรันด้วยสตรีมเป็นอินพุตtailให้เก็บnบัฟเฟอร์ -line ว่ามันเติมเมื่ออ่านสตรีม แต่ไม่สามารถส่งออกบรรทัดเหล่านั้นจนกว่าจะถึงจุดสิ้นสุดของสตรีมนั่นคือได้รับEOFรหัสพิเศษเมื่อพยายามอ่านจากอินพุต กระแส. การร้องขอtail -fไม่ออกดังนั้นจะไม่ปิดสตรีมซึ่งทำให้ไม่สามารถส่งคืนบรรทัดสุดท้ายที่ 10 ของสตรีมนั้นได้


3

ฟังก์ชั่นของtailคือการแสดงส่วนสุดท้าย - "หาง" - ของอินพุตหรือไฟล์ (ตัวเลือก-fเป็นเรื่องเกี่ยวกับสิ่งที่จะทำในภายหลังเพื่อไม่เกี่ยวข้องที่นี่)

ลองคิดดูไฟล์:

อะไรคือสิ่งที่ส่วนสุดท้ายของไฟล์ ?
สมมุติว่ามันคือn บรรทัดสุดท้ายของไฟล์

เมื่อเราอ่านบรรทัดiไฟล์อินพุตจะต้องตัดสินใจว่าจะพิมพ์อย่างไร
เราไม่ทราบว่าเป็นส่วนสุดท้าย - เพราะเราไม่ทราบว่าบรรทัดสุดท้ายจะเป็นเช่นไร ดังนั้นเราไม่สามารถพิมพ์ได้ตอนนี้

เราจำเป็นต้องเก็บสายไว้จนกว่าจะเห็นได้ชัดว่าเป็นส่วนหนึ่งของnบรรทัดสุดท้ายหรือไม่สามารถเป็นส่วนหนึ่งของมันได้nอีกต่อไปเพราะเรารู้ว่ามีบรรทัดต่อไป

หากตอนนี้เรามาถึงจุดสิ้นสุดของไฟล์แล้วเรารู้ว่าnบรรทัดสุดท้ายที่เราเก็บไว้นั้นเป็นจริงแล้วเป็นnบรรทัดสุดท้ายของไฟล์

ตอนนี้ในกรณีของ

tail -f /etc/passwd | tail

ครั้งแรกที่tailอ่านไฟล์แล้วรอรับข้อมูลเพิ่มเติมจากมันเพื่อเขียนออกมาเช่นกัน ดังนั้นมันจะไม่ส่งสัญญาณการสิ้นสุดของไฟล์ไปยังหางที่สองเมื่อมาถึงจุดสิ้นสุดของไฟล์ที่อ่าน หากไม่มีตัวที่สองtail จะไม่ได้รับการแจ้งเตือนเมื่อสิ้นสุดไฟล์ดังนั้นจึงไม่สามารถหาได้ว่าเป็นบรรทัดสุดท้ายที่ควรพิมพ์

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