ทำไม awk ทำบัฟเฟอร์เต็มเมื่ออ่านจากไปป์


23

ฉันกำลังอ่านจากพอร์ตอนุกรมที่เชื่อมต่อกับอุปกรณ์ gps ส่งสตริง nmea

การร้องขอที่เรียบง่ายเพื่อแสดงจุดของฉัน:

  $ awk '{ print $0 }' /dev/ttyPSC9 
  GPGGA,073651.000,6310.1043,N,01436.1539,E,1,07,1.0,340.2,M,33.3,M,,0000*56
  $GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39
  $GPRMC,073651.000,A,6310.1043,N,01436.1539,E,0.42,163.42,070312,,,A*67
  GPGGA,073652.000,6310.1043,N,01436.1540,E,1,07,1.0,339.2,M,33.3,M,,0000*55
  $GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39

ถ้าฉันลองอ่านจากไปป์ให้ awk บัฟเฟอร์อินพุตก่อนที่จะส่งไปยัง stdout

$ cat /dev/ttyPSC9 | awk '{ print $0 }'
<long pause>
GPGGA,073651.000,6310.1043,N,01436.1539,E,1,07,1.0,340.2,M,33.3,M,,0000*56
$GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39
$GPRMC,073651.000,A,6310.1043,N,01436.1539,E,0.42,163.42,070312,,,A*67
GPGGA,073652.000,6310.1043,N,01436.1540,E,1,07,1.0,339.2,M,33.3,M,,0000*55
$GPGSA,A,3,28,22,09,27,01,19,17,,,,,,2.3,1.0,2.0*39

ฉันจะหลีกเลี่ยงการบัฟเฟอร์ได้อย่างไร

แก้ไข : Kyle Jones แนะนำว่าแมวกำลังบัฟเฟอร์มันเป็นเอาต์พุต แต่ดูเหมือนจะไม่เกิดขึ้น:

$ strace cat /dev/ttyPSC9 | awk '{ print $0 }'
write(1, "2,"..., 2)                    = 2
read(3, "E"..., 4096)                   = 1
write(1, "E"..., 1)                     = 1
read(3, ",0"..., 4096)                  = 2

เมื่อฉันคิดเกี่ยวกับมันฉันคิดว่าโปรแกรมใช้การบัฟเฟอร์บรรทัดเมื่อเขียนถึงเทอร์มินัลและ "การบัฟเฟอร์ปกติ" สำหรับกรณีอื่น ๆ ทั้งหมด จากนั้นทำไมแมวถึงไม่บัฟเฟอร์มากขึ้น? พอร์ตอนุกรมส่งสัญญาณ EOF หรือไม่ แล้วทำไมแมวถึงไม่เลิก?


1
BashFAQ 009อาจมีประโยชน์
jw013

@ jw013: ขอบคุณสำหรับลิงค์สรุปยอดเยี่ยมเกี่ยวกับการทำงานของบัฟเฟอร์ใน bash
Daniel Näslund

คำตอบ:


10

มันน่าจะเป็นบัฟเฟอร์ใน awk ไม่ใช่แมว ในกรณีแรก awk เชื่อว่ามันเป็นแบบโต้ตอบเพราะอินพุตและเอาต์พุตเป็น TTY (แม้ว่าพวกเขาจะเป็น TTY ที่แตกต่างกัน - ฉันเดาว่า awk ไม่ได้ตรวจสอบสิ่งนั้น) ในวินาทีอินพุตเป็นไพพ์ดังนั้นจึงรันแบบไม่โต้ตอบ

คุณจะต้องล้างข้อมูลในโปรแกรม awk ของคุณอย่างชัดเจน แม้ว่ามันจะไม่สามารถพกพาได้

สำหรับพื้นหลังและรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการล้างเอาต์พุตอ่าน: http://www.gnu.org/software/gawk/manual/html_node/I_002fO-Functions.html


6
ขอบคุณสำหรับคำอธิบาย awk -W interactive '{print $0}'ดูเหมือนจะทำเคล็ดลับ 'W interactiveตัวเลือกที่มีอยู่ในรุ่น awk ของฉัน (mawk 1.2) แต่ผมไม่รู้ว่ามันเป็นตัวเลือกที่ได้มาตรฐาน
Daniel Näslund

1
@dannas -Wไม่ได้อยู่ในมาตรฐาน POSIX awkสำหรับ ฉันไม่แน่ใจว่าจะทำอย่างไรถ้าคุณต้องการพกพาได้สูงสุด
jw013

ฉันยอมรับคำตอบนี้เนื่องจากอธิบายว่าเหตุใด awk กำลังทำการบัฟเฟอร์แบบเต็มในตัวอย่างของฉันแทนที่จะเป็นการบัฟเฟอร์บรรทัด - ตรวจสอบว่าอินพุตเป็น tty เช่นเดียวกับเอาต์พุตหรือไม่ ฉันแค่คิดว่ามันจะตรวจสอบผลลัพธ์
Daniel Näslund

@ jw013: ขอบคุณที่มองหามาตรฐาน สำหรับฉันฉันแค่อยากจะเข้าใจว่าทำไม awk กำลังทำการบัฟเฟอร์เต็มรูปแบบและฉันคิดว่าฉันทำตอนนี้
Daniel Näslund

@dannas ฉันสามารถยืนยันได้ว่า-W interactiveมีการรองรับอย่างน้อยที่สุดในการแจกจ่าย Ubuntu 12.04 (และใหม่กว่า) ของ awk ซึ่งเป็น mawk
Jason C

37

ฉันรู้ว่ามันเป็นคำถามเก่า แต่หนึ่งซับอาจช่วยให้ผู้ที่มาที่นี่ค้นหา:

cat /dev/ttyPSC9 | awk '{ print $0; system("")}'

system("")หลอกลวงและเป็นไปตาม POSIX ระบบที่ไม่ใช่ posix: ระวัง

มีฟังก์ชั่นที่เฉพาะเจาะจงมากขึ้นfflush()ที่ทำเช่นเดียวกัน แต่ไม่สามารถใช้ได้ใน awk รุ่นเก่า

ข้อมูลชิ้นสำคัญจากเอกสารเกี่ยวกับการใช้system(""):

gawk ปฏิบัติต่อการใช้งานฟังก์ชัน system () นี้เป็นกรณีพิเศษและฉลาดพอที่จะไม่เรียกใช้เชลล์ (หรือล่ามคำสั่งอื่น ๆ ) ด้วยคำสั่งว่าง ดังนั้นด้วยเพ่งพิศ, สำนวนนี้ไม่เพียงมีประโยชน์ แต่ยังมีประสิทธิภาพ


สิ่งนี้ใช้ได้ผลสำหรับฉัน
ซ้ำ

3
ฉันawkไม่ได้ทำอะไรเกี่ยวกับค่ามิได้fflush() system("")ฉันgawkรู้สึกเป็นเกียรติแม้ว่า
Krzysztof Jabłoński
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.