นับจำนวนไบต์ piped จากกระบวนการหนึ่งไปยังกระบวนการอื่น


17

ฉันใช้เชลล์สคริปต์ที่ท่อข้อมูลจากกระบวนการหนึ่งไปยังกระบวนการอื่น

process_a | process_b

ไม่มีใครรู้วิธีหาจำนวนไบต์ที่ถูกส่งระหว่างโปรแกรมทั้งสอง? ทางออกเดียวที่ฉันสามารถนึกได้ในขณะนี้คือการเขียนโปรแกรม c ขนาดเล็กที่อ่านจาก stdin, เขียนไปยัง stdout และนับจำนวนข้อมูลที่ถ่ายโอนทั้งหมด, จัดเก็บจำนวนในตัวแปรสภาพแวดล้อมเช่น:

process_a | count_bytes | process_b

ไม่มีใครมีวิธีแก้ปัญหา neater?

คำตอบ:


16

ท่อผ่าน dd อินพุตดีฟอลต์ของ dd คือ stdin และเอาต์พุตดีฟอลต์คือ stdout; เมื่อเสร็จสิ้นการ stdin / stdout I / O มันจะรายงานไปยัง stderr เกี่ยวกับจำนวนข้อมูลที่ถ่ายโอน

หากคุณต้องการจับเอาท์พุทของ dd และโปรแกรมอื่น ๆ คุยกับ stderr แล้วให้ใช้ file-descriptor ตัวอื่น เช่น,

$ exec 4>~/fred
$ input-command | dd 2>&4 | output-command
$ exec 4>&-

2
คุณไม่สามารถข้ามexecและส่งออกไปยังไฟล์ได้โดยตรงหรือไม่ input-command | dd 2>~/fred | output-command
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

2
เอ่อใช่ เห็นได้ชัดว่าฉันมีช่วงเวลาหนึ่ง "เหล่านั้น" ขอโทษ
Phil P

28

ใช้pvไปป์วิวเวอร์ มันเป็นเครื่องมือที่ยอดเยี่ยม เมื่อคุณรู้เรื่องนี้แล้วคุณจะไม่มีทางรู้ว่าคุณอยู่โดยปราศจากมันได้อย่างไร

นอกจากนี้ยังสามารถแสดงแถบความคืบหน้าและความเร็วในการโอน


ในการค้นหาของฉันฉันได้พบสิ่งนี้ แต่ฉันต้องการให้ตั้งค่าตัวแปรด้วยจำนวนไบต์ที่ถ่ายโอนเพื่อที่ฉันจะสามารถใช้มันในกระบวนการอื่นได้
Simon Hodgson

ตัวอย่างการใช้งาน: cat file | pv -bจะคืนขนาดไฟล์
rodorgas

6

process_a | tee >(process_b) | wc --bytesอาจทำงานได้ จากนั้นคุณสามารถเปลี่ยนเส้นทางwcไปยังที่ที่คุณต้องการ ถ้าprocess_bอะไรที่จะเอาท์พุทstdout/ คุณอาจจะต้องเปลี่ยนเส้นทางออกนี้ที่ไหนสักแห่งถ้าเพียงstderr/dev/null

สำหรับตัวอย่างที่วางแผนไว้เล็กน้อย:

filestore:~# cat document.odt | tee >(dd of=/dev/null 2>/dev/null) | wc --bytes
4295

โดยวิธีการอธิบาย: teeช่วยให้คุณสามารถส่งออกโดยตรงไปยังไฟล์หลาย ๆ ไฟล์ (บวก stdout) และ>()โครงสร้างของ bash คือ "การทดแทนกระบวนการ" ซึ่งทำให้กระบวนการมีลักษณะเหมือนไฟล์แบบเขียนอย่างเดียวในกรณีนี้เพื่อให้คุณสามารถเปลี่ยนเส้นทางไปยังกระบวนการต่างๆ ดูที่นี่หรือคำถามนี้ + คำตอบสำหรับตัวอย่างของการใช้teeเพื่อส่งผลลัพธ์ไปยังกระบวนการต่างๆ)


ฉันชอบวิธีนี้น่าเสียดายที่ shelll ที่ฉันใช้อยู่ (BusyBox) ไม่สนับสนุนสัญกรณ์> () แต่มันให้วิธีการทำสิ่งที่ฉันตามมา
ไซมอนฮอดจ์สัน

ใช่คุณต้องทุบตีอย่างสมบูรณ์เพื่อให้มีคุณสมบัตินั้น - มันเป็นสิ่งที่ไม่ได้ใช้กันทั่วไปเพื่อให้ได้เปลือกหอยที่ถูกตัดออก (แม้แต่คนที่มีเป้าหมายที่จะเข้ากันได้กับทุบตีมากขึ้นหรือน้อยลง) ชอบ busybox เพื่อประหยัดพื้นที่
David Spillett

1

ฉันรู้ว่าฉันไปงานปาร์ตี้สาย แต่ฉันเชื่อว่าฉันมีคำตอบที่ดีซึ่งสามารถปรับปรุงหัวข้อนี้มีประโยชน์
นี่คือการผสมผสานระหว่าง @Phil P และ @David Spillett คำตอบ แต่:

  • แตกต่างจาก @Phil P มันหลีกเลี่ยงการสร้างไฟล์ใหม่
  • แตกต่างจาก @David Spillett 's, มันรักษาโครงสร้างไปป์ไลน์

Bytes-count ถูกพิมพ์ไปยัง stdout พร้อมกับเอาต์พุตของ process_b ใด ๆ
คุณสามารถใช้คำนำหน้าเพื่อระบุบรรทัดที่มีไบต์เมื่อทำงานกับเอาต์พุต ( Bytes:ในตัวอย่าง)

exec 3>&1
process_a | tee >({ echo -n 'Bytes:'; wc -c; } >&3) | process_b
exec 3>&-

คำเตือน:
อย่าพึ่งพาลำดับของบรรทัดในเอาต์พุต
ลำดับที่คาดเดาไม่ได้และสามารถแตกต่างกันได้เสมอแม้ว่าจะเรียกสคริปต์เดียวกันด้วยพารามิเตอร์เดียวกัน!


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