ท่อด้วย Moreutils ts


9

ฉันมีสตรีมขาเข้าที่พอร์ตอนุกรมโดยมีบรรทัดใหม่ปรากฏขึ้นหนึ่งครั้งต่อวินาที

wren@Raven:~$ cat /dev/ttyUSB0

A_Sensor1,B_22.00,C_50.00

A_Sensor1,B_22.00,C_50.00

A_Sensor1,B_22.00,C_50.00

A_Sensor1,B_22.00,C_50.00

A_Sensor1,B_22.00,C_50.00

ฉันต้องการตัดเส้นที่ว่างเปล่าและประทับเวลาที่เหลือ

sed จะเลือกบรรทัดว่างและเพิ่มการประทับเวลา แต่ฉันไม่สามารถอัปเดตการประทับเวลาได้เพียงรายงานเวลาที่เรียกใช้:

wren@Raven:~$ cat /dev/ttyUSB0 | sed -e '/^$/d' -e "s/$/`date +\,%F\,%T`/"
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
^C

ฉันได้พบ ts ส่วนหนึ่งของ Moreutils และสามารถเข้าไปในนั้นเพื่อรับการบันทึกเวลาที่อัปเดต

wren@Raven:~$ cat /dev/ttyUSB0 |  ts
May 14 09:49:26 A_Sensor1,B_22.00,C_50.00
May 14 09:49:26
May 14 09:49:27 A_Sensor1,B_22.00,C_50.00
^C

อย่างไรก็ตามฉันไม่สามารถรวม ts กับ sed ได้อย่างถูกต้อง

สิ่งนี้ซึ่งดูเหมือนว่าควรจะทำในสิ่งที่ฉันต้องการไม่มีผลผลิตเลย

wren@Raven:~$ cat /dev/ttyUSB0 | sed -e '/^$/d' | ts
^C
wren@Raven:~$

อย่างไรก็ตามการกลับคำสั่งของท่อจะสร้างผลลัพธ์ แต่แน่นอนไม่ได้ตัดเส้นซึ่งไม่มีความว่างเปล่าอีกต่อไป การทดแทนอื่น ๆ ทำงานได้ดีดังนั้นฉันจึงรู้ว่าไปป์ Sed เพื่อทำงาน

wren@Raven:~$ cat /dev/ttyUSB0 |  ts | sed -e '/^$/d'
May 14 10:07:25 A_Sensor1,B_22.00,C_50.00
May 14 10:07:25
May 14 10:07:26 A_Sensor1,B_22.00,C_50.00
May 14 10:07:26
^C

ดังนั้นฉันรู้สึกงุนงงเล็กน้อย ฉันสามารถทำให้ sed ลบเส้นที่ไม่ต้องการออกได้ แต่การประทับเวลาก่อนที่จะนำออกต้องเป็นวิธีที่ผิด

ฉันขอขอบคุณคำอธิบายและความช่วยเหลือ

คำตอบ:


9

ในการตอบคำถามโดยตรงsedคือการบัฟเฟอร์และนั่นเป็นปัญหา แต่เพียงผู้เดียว
คุณสามารถแก้ไขได้โดยบอกไม่ให้บัฟเฟอร์ด้วย-u/ --unbufferedflag:

sed -u '/^$/d' /dev/ttyUSB0 | ts

ด้วยสายรัดทดสอบ (แต่คุณจะต้องใช้เพื่อพิสูจน์):

$ (echo -e 'banana\n\n'; sleep 2; echo 'cheese') | sed -u '/^$/d' | ts
May 14 11:26:05 banana
May 14 11:26:07 cheese

คุณสามารถพบกับเหน็บแนมที่คล้ายกันด้วยโปรแกรมแก้ไขสตรีมอื่น ๆ ดูเหมือนว่าพวกเขาทั้งหมดต้องการบัฟเฟอร์เล็กน้อย พวกเขาทั้งหมดมีวิธีแก้ปัญหาว่า นี่คือคำสั่งมากมายที่ฉันได้ทดสอบ:

... | mawk -W interactive '/./' | ts
... | gawk '/./ { print $0; fflush(); }' | ts
... | grep --line-buffered '.' | ts
... | perl -n -e 'print if /./' | ts

อีกแนวคิดหนึ่งก็คือให้gawkจัดการกับมัน มันสามารถกรองสำหรับบรรทัดที่ไม่ว่างเปล่าและทำการพิมพ์วันที่ให้คุณ (ขอบคุณKieronของ SO ):

awk '/./ { print strftime("%Y-%m-%d %H:%M:%S"), $0; fflush(); }' /dev/ttyUSB0

การล้างข้อมูลหลังจากที่บรรทัดเข้ามาgawkมีประโยชน์เป็นพิเศษที่นี่หากคุณต้องการทำสิ่งอื่น ... หากคุณต้องการตรวจสอบว่าคอลัมน์ที่สี่ของเอาต์พุต (ก่อน - ts) ตรงกับ regex คุณสามารถ (เช่น$4~/\d{4}/) Awk (และตัวแปร) มีความยืดหยุ่นสูงสำหรับการประมวลผลแบบสตรีม

สายรัดทดสอบอื่น:

$ gawk '/./ { print strftime("%Y-%m-%d %H:%M:%S"), $0; fflush(); }' <(
      echo -e 'banana\n\n';
      sleep 2;
      echo 'cheese'
  )
2014-05-14 11:13:59 banana
2014-05-14 11:14:01 cheese

1
+1 sed -uสำหรับ มันเป็นปัญหาการบล็อกบัฟเฟอร์และการบัฟเฟอร์บรรทัด
jfs

@Oli sed -u ยังทำงานได้อย่างสมบูรณ์แบบเมื่อส่งไปยัง ts ดังนั้นฉันจะอ่านข้อมูลเกี่ยวกับการบัฟเฟอร์ ฉันไม่งุนงงอีกต่อไปแล้วขอบคุณมาก
งง

awk เหมาะอย่างยิ่งสำหรับสิ่งต่าง ๆ เช่นนี้ รหัส awk โดยทั่วไปจะมีความหนาแน่นน้อยกว่าและอ่านได้ง่ายกว่า sed และคุณสามารถใส่คำสั่งการพิมพ์ได้มากเท่าที่คุณต้องการดูผลลัพธ์บางส่วนขณะทำการดีบัก คุณสามารถใส่โปรแกรม awk ทั้งหมดลงในเอกสาร here ที่นี่เพื่อหลีกเลี่ยงการใช้ไฟล์แยกกันและถ้าคุณใส่เครื่องหมายคำพูดรอบ ๆ สตริงเอกสาร terminator here การทุบตีจะไม่สนใจโทเค็นที่ฝังอยู่ทั้งหมดโดยปกติแล้วจะพยายามตีความ
Joe

0

ทุบตีสามารถจัดการนี้ในwhile readวง

(echo -e 'banana\n\n'; sleep 2; echo 'cheese') | 
while IFS= read -r line; do 
    [[ $line ]] && echo "$(date "+%F %T") line"
done
2014-05-14 06:34:06 banana
2014-05-14 06:34:08 cheese

คุณสามารถลบบรรทัดด้วยช่องว่างเท่านั้นที่มีการขยายพารามิเตอร์หากิน: ลบช่องว่างนำหน้าทั้งหมดและดูว่าบรรทัดว่างเปล่า:

shopt -s extglob

(echo -e '  banana\n\t\n'; sleep 2; echo 'cheese') |
while IFS= read -r line; do
    [[ "${line/#+([[:blank:]])/}" ]] && echo "$(date "+%F %T") $line"
done

ฉันลองใช้วิธีการที่หลากหลายเช่นนั้นไม่มีวิธีใดที่ทำงานได้ ฉันไม่สามารถรับรหัสของคุณให้ทำงานได้ การใช้ echo หรือ cat เพื่อส่ง / dev / ttyUSB0 ไปยัง while loop จะให้ผลลัพธ์ในบรรทัดเดียว: 2014-05-14 12:23:32 line
งง

ฉันแน่ใจว่ามีวิธีที่ดีกว่า แต่ลองtail -f /dev/ttyUSB0แทนแมวหรือเสียงก้อง มันจะวิ่งต่อไป ฉันไม่รู้วิธีทดสอบสิ่งนี้ในระบบของฉัน
Joe

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