Rurociągi z Moreutils ts


9

Mam przychodzący strumień do portu szeregowego, a nowe linie pojawiają się mniej więcej raz na sekundę

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

Chcę usunąć puste linie i datownik resztę.

sed usunie puste wiersze i doda znacznik czasu, ale nie mogę zaktualizować znacznika czasu, po prostu zgłasza czas jego wywołania:

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

Znalazłem ts, część Moreutils, i mogę do niego podłączyć, aby uzyskać znacznik czasu aktualizacji.

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

Jednak nie mogę poprawnie połączyć ts z sed.

To, które wygląda na to, że powinno robić to, co chcę, nie generuje w ogóle żadnych wyników

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

Jednak odwrócenie kolejności rur daje wynik, ale oczywiście nie usuwa linii, które nie są już puste. Inne substytucje działają dobrze, więc wiem, że fajka do sed działa.

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

Więc jestem trochę zaskoczony. Mogę przypuszczalnie sprawić, by sed usunął niechciane linie, ale znacznik czasu przed usunięciem musi być niewłaściwy.

Byłbym wdzięczny za wyjaśnienie i pomoc.

Odpowiedzi:


9

Bezpośrednia odpowiedź na pytanie sedjest buforowaniem i to jest jedyny problem.
Możesz to naprawić, mówiąc, aby nie buforował za pomocą flagi -u/ --unbuffered:

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

Z uprzężą testową (ale musisz ją uruchomić, aby uzyskać dowód):

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

Możesz spotkać podobne problemy z innymi edytorami strumieniowymi. Najwyraźniej wszyscy chcą trochę buforować. Wszystkie mają jednak obejścia. Oto kilka poleceń, które przetestowałem:

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

Innym pomysłem jest po prostu gawksobie z tym poradzić. Może filtrować niepuste linie i drukować dla ciebie datę (dzięki Kieronowi SO ):

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

To opróżnia się zaraz po wejściu linii. gawkJest to szczególnie pomocne, jeśli chcesz zrobić inne rzeczy ... Jeśli chcesz sprawdzić, czy czwarta kolumna wyniku (pre- ts) pasuje do wyrażenia regularnego, możesz (np $4~/\d{4}/.). Awk (i jego warianty) są bardzo elastyczne w przetwarzaniu strumieniowym.

Kolejna uprząż testowa:

$ 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 dla sed -u. Jest to kwestia buforowania bloków vs. buforowania linii.
jfs

@Oli sed -u działa również idealnie po podłączeniu do ts, więc przeczytam o buforowaniu. Nie jestem już zaskoczony, wielkie dzięki.
zakłopotany

awk jest szczególnie odpowiedni do takich rzeczy. Kod awk jest ogólnie o wiele mniej gęsty i znacznie bardziej czytelny niż sed i możesz wrzucić tyle instrukcji drukowania, ile chcesz zobaczyć częściowe wyniki podczas debugowania. Możesz umieścić cały program awk w dokumencie tutaj, aby uniknąć używania osobnego pliku, a jeśli wstawisz cudzysłowy wokół ciągu terminatora dokumentu tutaj, bash zignoruje wszystkie osadzone tokeny, które normalnie próbowałby interpretować.
Joe

0

bash poradzi sobie z tym w while readpętli

(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

Możesz usuwać linie tylko z białymi spacjami z trudnym rozszerzaniem parametrów: usuń wszystkie wiodące białe spacje i sprawdź, czy linia jest pusta:

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

Próbowałem różnych podejść, ale żadne z nich nie działało. Nie mogę też uruchomić twojego kodu. Użycie echa lub kota do wysłania / dev / ttyUSB0 do pętli while powoduje powstanie pojedynczego wiersza wyjścia: wiersz 2014-05-14 12:23:32
zakłopotany

Jestem pewien, że jest lepszy sposób, ale spróbuj tail -f /dev/ttyUSB0zamiast kota lub echa. Będzie działać. Nie wiedziałem, jak to sprawdzić w moim systemie.
Joe

tail -f / dev / ttyUSB0 nie daje danych wyjściowych, z pętlą while lub bez niej. tvm za komentarze.
zakłopotany
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.