ฉันสามารถปิดการใช้งานการบัฟเฟอร์สำหรับ tr


10

trดูเหมือนว่าจะบัฟเฟอร์อินพุตเพื่อให้คำสั่งนี้LongRunningCommand|tr \\n ,จะเริ่มผลิตผลลัพธ์หลังจากอินพุตไม่กี่กิโลไบต์จาก LongRunningCommand สะสม

มีวิธีบังคับtrให้หยุดการบัฟเฟอร์นี้หรือคำสั่งอื่นใดที่สามารถแทนที่บรรทัดใหม่ด้วยอักขระอื่นโดยไม่บัฟเฟอร์หรือไม่?


ป.ล. ฉันได้ลองคำแนะนำสองข้อแรกจากปิดการบัฟเฟอร์ในท่อไม่สำเร็จ


1
คุณใช้stdbufกับ LongRunningCommand หรือ tr หรือทั้งสองอย่างแตกต่างกันหรือไม่?
meuh

ทั้งสองอย่างเช่นนี้:stdbuf -o0 fping -aAq -r2 -g 10.30.0.1 10.30.0.255 2>/dev/null | stdbuf -i0 tr \\n ,
58

fping -qพูดว่า "อย่าแสดงผลลัพธ์แบบโพรบต่อ แต่เป็นเพียงบทสรุปขั้นสุดท้าย" ดังนั้นบางทีมันอาจจะเขียนได้นานแค่ปลายเดียว?
meuh

ไม่มีคำสั่ง fping ทำงานได้เอง ขอบคุณมากสำหรับคำแนะนำแม้ว่า
ndemou

2
ผมคิดว่าปัญหาบัฟเฟอร์ที่เป็นจริงในการส่งออกtrของ ลอง|stdbuf -i0 -o0 tr ...
meuh

คำตอบ:


12

คำสั่งโดยทั่วไปจะไม่บัฟเฟอร์อินพุตของพวกเขา พวกเขาจะทำread()สำหรับก้อนขนาดใหญ่ แต่เมื่ออ่านจากไปป์ถ้ามีไม่กี่ไบต์ในไปป์การread()เรียกของระบบจะกลับมาพร้อมกับตัวอักษรจำนวนมากที่มีอยู่และโดยทั่วไปแอปพลิเคชันจะทำงานด้วยถ้ามันสามารถ .

ข้อยกเว้นที่น่าสังเกตซึ่งเป็นmawkสิ่งที่จะทำread()ต่อไปจนกว่าบัฟเฟอร์อินพุตจะเต็ม

แอ็พพลิเคชันทำบัฟเฟอร์เอาต์พุตของตน(stdout) แม้ว่า พฤติกรรมปกติคือถ้าเอาท์พุทจะไป tty แล้วการบัฟเฟอร์จะเป็นบรรทัดที่ชาญฉลาด (นั่นคือมันจะไม่เริ่มเขียนไปยัง stdout จนกว่าจะมีสายเต็มไปยังเอาท์พุทหรือบล็อกเต็มสำหรับมาก สายยาว) ในขณะที่ไฟล์ประเภทอื่นทุกประเภทการบัฟเฟอร์คือโดยบล็อก (นั่นคือมันจะไม่เริ่มเขียนจนกว่าจะมีหนึ่งบล็อกเต็มในการเขียน (บางอย่างเช่น 4KiB / 8KiB ... ขึ้นอยู่กับซอฟต์แวร์และระบบ ))

ดังนั้นในกรณีของคุณLongRunningCommandอาจบัฟเฟอร์ส่งออกโดยบล็อก (เนื่องจากเอาท์พุทเป็นท่อและไม่ใช่ tty) และtrมีแนวโน้มบัฟเฟอร์เอาต์พุตโดยบรรทัดเนื่องจากเอาต์พุตอาจเป็นเทอร์มินัล

แต่เนื่องจากคุณลบอักขระบรรทัดใหม่ทุกตัวออกจากเอาต์พุตมันจะไม่ส่งออกบรรทัดดังนั้นการบัฟเฟอร์จะเป็นบล็อก

ดังนั้นที่นี่คุณต้องการที่จะปิดการใช้งานสำหรับทั้งบัฟเฟอร์และLongRunningCommand trบนระบบ GNU หรือ FreeBSD:

stdbuf -o0 LongRunningCommand | stdbuf -o0 tr '\n' ,

paste -sd , -หมายเหตุว่าถ้าคุณต้องการที่จะเข้าร่วมสายด้วยเครื่องหมายจุลภาคเป็นวิธีการที่ดีคือการใช้งาน ด้วยวิธีนี้ผลลัพธ์จะถูกยกเลิกด้วยอักขระขึ้นบรรทัดใหม่ (คุณอาจต้องปิดการใช้งานการบัฟเฟอร์)


@mikeserv ใช่และอีกตัวที่ใช้ stdio buffering และไม่เรียก setvbuf / setbuffer ... ด้วยตัวเองและไม่ใช่ shell builtin แต่โดยทั่วไปในระบบ GNU และ FreeBSD เงื่อนไขเหล่านั้นเป็นที่พอใจ
Stéphane Chazelas

โอ้ ผมได้เรียนรู้ แต่เพียงว่าตัวเองไม่กี่วันที่ผ่านมาเมื่อผมผิดหวังที่ผมไม่สามารถส่งผลกระทบต่อ I / o sedลำธารสำหรับรวบรวมแบบคงที่ของฉัน ขออภัยถ้ามันน่ารำคาญ - แต่ฉันไม่รู้ว่ามันเป็นความรู้ทั่วไป ฉันเดาว่ามันใช้ LD_PRELOAD
mikeserv

ขอบคุณสำหรับคำอธิบายอย่างละเอียดว่าเกิดอะไรขึ้นกับStéphane ได้รับการชื่นชมอย่างมาก
ndemou

5

หากต้องการแทนที่บรรทัดใหม่ด้วย","คุณสามารถเรียกใช้

awk '{ printf "%s,", $0 }'

GNU awk ( gawk) และ Solaris nawkจะทำงานโดยมีการบัฟเฟอร์บรรทัดบน stdin และไม่มีการบัฟเฟอร์ stdout เมื่อเอาต์พุตเป็นเทอร์มินัล หาก awk ของคุณคือmawkสิ่งที่เกิดขึ้นกับ Ubuntu คุณสามารถให้-W interactiveตัวเลือกเพื่อรับพฤติกรรมการบัฟเฟอร์แบบเดียวกัน

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