Perpipaan dengan Moreutils ts

9

Saya memiliki aliran masuk di port serial, dengan baris baru muncul sekitar satu kali per detik

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

Saya ingin menghapus garis kosong dan mencatat waktu sisanya.

sed akan menyisihkan baris kosong dan menambahkan timestamp, tapi saya tidak bisa membuat pembaruan timestamp, itu hanya melaporkan waktu itu dipanggil:

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

Saya telah menemukan ts, bagian dari Moreutils, dan dapat menyalurkan ke dalamnya untuk mendapatkan cap waktu pembaruan.

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

Namun, saya tidak bisa menggabungkan ts dengan sed.

Ini, yang sepertinya harus melakukan apa yang saya inginkan, tidak menghasilkan output sama sekali

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

Namun membalik urutan pipa memang menghasilkan output, tetapi tentu saja tidak menghilangkan garis yang tidak lagi kosong. Penggantian lainnya berfungsi dengan baik, jadi saya tahu pipa untuk sed berfungsi.

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

Jadi saya agak bingung. Saya mungkin bisa membuat sed menghapus garis yang tidak diinginkan, tetapi timestamping sebelum penghapusan harus menjadi pendekatan yang salah.

Saya akan sangat menghargai penjelasan dan bantuan.

bingung
sumber

Jawaban:

9

Untuk menjawab pertanyaan secara langsung, sedadalah buffering dan itulah satu-satunya masalah.
Anda dapat memperbaikinya dengan mengatakannya agar tidak buffer dengan -u/ --unbufferedflagnya:

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

Dengan test harness (tetapi Anda harus menjalankannya sebagai bukti):

$ (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

Anda dapat mengalami kesulitan serupa dengan editor aliran lainnya. Mereka tampaknya semua ingin sedikit buffer. Mereka semua memiliki solusi. Berikut adalah banyak perintah yang telah saya uji:

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

Gagasan lain adalah membiarkannya gawk. Ini dapat memfilter untuk saluran yang tidak kosong dan melakukan pencetakan tanggal untuk Anda (terima kasih kepada SO's Kieron ):

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

Itu memerah langsung setelah garis masuk. Sangat gawkmembantu di sini jika Anda ingin melakukan hal - hal lain ... Jika Anda ingin memeriksa bahwa kolom keempat output (pra- ts) cocok dengan regex, Anda dapat (misalnya $4~/\d{4}/). Awk (dan variannya) sangat fleksibel untuk pemrosesan aliran.

Alat uji lain:

$ 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
Oli
sumber
1
+1 untuk sed -u. Ini adalah masalah block-buffering vs line-buffering.
jfs
@Oli sed -u juga berfungsi dengan baik ketika disalurkan ke ts, jadi saya akan membaca tentang buffering. Saya tidak lagi bingung, terima kasih banyak.
Bingung
awk sangat cocok untuk hal-hal seperti ini. kode awk umumnya jauh lebih padat dan jauh lebih mudah dibaca daripada sed dan Anda dapat memasukkan sebanyak-banyaknya pernyataan cetak yang Anda inginkan untuk melihat hasil parsial saat debugging. Anda bisa memasukkan seluruh program awk ke dalam dokumen di sini untuk menghindari penggunaan file terpisah dan jika Anda memberi tanda kutip di sekitar string terminator dokumen di sini, maka bash akan mengabaikan semua token yang disematkan yang biasanya akan diinterpretasikan.
Joe
0

bash dapat menangani ini dalam satu while readlingkaran

(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

Anda dapat menghapus baris dengan spasi kosong saja dengan ekspansi parameter yang rumit: hapus semua spasi kosong terkemuka dan lihat apakah baris kosong:

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
glenn jackman
sumber
Saya mencoba berbagai pendekatan seperti itu, tidak ada yang berhasil. Saya juga tidak bisa membuat kode Anda berfungsi. Menggunakan gema atau kucing untuk mengirim / dev / ttyUSB0 ke loop sementara hanya menghasilkan satu baris output: 2014-05-14 12:23:32 line
bingung
Saya yakin ada cara yang lebih baik, tetapi coba tail -f /dev/ttyUSB0daripada cat atau echo. Itu akan terus berjalan. Saya tidak tahu bagaimana cara menguji ini pada sistem saya.
Joe
tail -f / dev / ttyUSB0 tidak memberikan output, dengan atau tanpa loop while. TVM untuk komentar Anda.
Bingung