Пайпинг с Мореутилс тс

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особенно полезно, если вы хотите заняться другими делами ... Если вы хотите проверить, соответствует ли четвертый столбец вывода (pre 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 в документ here, чтобы избежать использования отдельного файла, и если вы поместите кавычки вокруг строки терминатора здесь, bash проигнорирует все встроенные токены, которые он обычно пытается интерпретировать.
Джо
0

Bash может справиться с этим в 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вместо кошки или эха. Это будет продолжаться. Я не знал, как проверить это в моей системе.
Джо
tail -f / dev / ttyUSB0 не выдает выходных данных с циклом while или без него. твм за ваши комментарии.
озадачен