Трубопроводи з Мореутілсом ц


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

Однак я не можу правильно поєднувати тс з 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впоратися. Він може фільтрувати непорожні рядки і робити друк дат для вас (дякуючи Кірону SO ):

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

Це спалах відразу після надходження рядків. gawkОсобливо корисно тут, якщо ви хочете робити інші речі ... Якщо ви хочете перевірити, чи відповідає четвертий стовпець стовпця (попереднього ts) регулярним виразом, ви можете (наприклад $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 в документ тут, щоб уникнути використання окремого файлу, і якщо ви поставите лапки навколо рядка термінатора документа тут, то bash ігнорує всі вбудовані маркери, які зазвичай намагатиметься інтерпретувати.
Джо

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 просто призводить до одного рядка виводу: 2014-05-14 12:23:32 рядок
здивований

Я впевнений, що є кращий спосіб, але спробуйте tail -f /dev/ttyUSB0замість кота чи відлуння. Це буде продовжувати працювати. Я не знав, як перевірити це на своїй системі.
Джо

хвіст -f / dev / ttyUSB0 не дає виводу, з циклом або без нього. ТВМ для ваших коментарів.
здивований
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.