перенаправить стандартный вывод в сценарий, чтобы его можно было проанализировать и затем отправить в стандартный вывод - PullRequest
1 голос
/ 07 февраля 2012

У меня есть программа (java), которая печатает строку шестнадцатеричных чисел в стандартный вывод каждые 5 секунд, пока программа не будет завершена пользователем.

Я бы хотел перенаправить этот вывод в скрипт bash, чтобыЯ мог бы преобразовать каждое из этих шестнадцатеричных чисел независимо в десятичное, а затем распечатать разобранную строку в стандартный вывод.

Я попытался с помощью myProgram |myScript, но это делало конвейер до того, как были напечатаны какие-либо строки, а затем не слушало стандартный вывод.Затем я попробовал myProgram> myScript, и это просто переписало скрипт.

Идеи?

Правка: добавление вывода из прогонов (извините за плохое форматирование, я не смог все это получитьв выделении кода), поэтому середина вывода не выделена).

Вот скрипт

#!/bin/bash
echo $0
echo $#
echo $1

Вот как моя программа работает, пока она идет прямо к stdout, это будет продолжатьсянавсегда, если я не прерву его.

mmmm@mmmm:~/mmmm/mmmm/mmmmm$ java net.tinyos.tools.Listen -comm 
serial@/dev/ttyUSB0:micaz
serial@/dev/ttyUSB0:57600: resynchronising   
00 FF FF 00 02 04 22 93 00 02 02 C9
00 FF FF 00 03 04 22 93 00 03 03 0E
00 FF FF 00 02 04 22 93 00 03 03 0E
00 FF FF 00 02 04 22 93 00 02 02 C9
^Z
[5]+  Stopped                 java net.tinyos.tools.Listen -comm          
serial@/dev/ttyUSB0:micaz

Вот где я пытаюсь передать его в свой скрипт (который я установил, чтобы вывести число аргументов командной строки и первый аргумент. Он просто зависаетпосле этого ...

mmmm@mmmm:~/mmmm/mmmm/mmmmm$$ java net.tinyos.tools.Listen -comm serial@/dev/ttyUSB0:micaz | ./parser.sh
./parser.sh
0
serial@/dev/ttyUSB0:57600: resynchronising

Ответы [ 3 ]

1 голос
/ 07 февраля 2012

Диагностика

Когда вы используете этот скрипт, как это:

java javaprog | myScript

и myScript содержит:

#!/bin/bash
echo $0
echo $#
echo $1

Тогда выводом скрипта будет его имя (myScript) из echo $0, количество аргументов, переданных ему (0) из echo $#, и первый аргумент (отображается пустая строка ) из echo $1. Затем скрипт завершает работу (успешно). Проблема не имеет ничего общего с буферизацией; все это связано с тем, что скрипт ничего не читает из стандартного ввода. Даже тривиальная модификация будет улучшением:

#!/bin/bash
while read data; do echo $data; done

Это более медленная форма cat, за исключением того, что она нормализует случайные последовательности пробелов и табуляций в единичные пробелы, удаляя начальные и конечные пробелы из строки. По крайней мере, он продемонстрировал бы сценарий, обрабатывающий вывод программы Java.


Пытаясь awk

Чтобы сделать то, что вам нужно, вам, вероятно, следует заменить это awk программой или чем-то подобным. Это первый черновик, но у него есть шанс на работу:

awk '{for(i = 1; i <= NF; i++) { x = "0x" $i + 0; printf(" %d", x); printf "\n";}'

Здесь написано «для каждой строки (потому что перед открывающей скобкой нет шаблона)», do »для каждого из полей 1..NF, преобразовать поле в явную шестнадцатеричную строку с префиксом 0x и добавить 0, затем выведите значение в виде десятичного числа (доверяя awk для преобразования строки, такой как '0xC9', в число).

Использование Perl

К сожалению, небольшое тестирование показывает, что это не работает; проблема заключается в получении значения, отличного от 0, для x. Итак, ... время вернуться к Perl в режиме awk -эмуляции:

$ echo '00 C9 28 13 A0 FF 01' |
> perl -na -e 'for ($i = 0; $i < scalar(@F); $i++) { printf(" %d", hex $F[$i]); }
>       printf "\n";'
 0 201 40 19 160 255 1
$

Это работает - это даже довольно легко понять. Опция -n означает «читать каждую строку данных и выполнять команды в сценарии в каждой строке (но не печатать $_ в конце)». Опция -a в сочетании с -n (как здесь, или -p, что похоже на -n, за исключением того, что она печатает $_ автоматически) означает «автоматически разбить входные данные на массив @F. Затем скрипт обрабатывает каждый элемент @F в каждой строке (довольно многословно), используя функцию hex для преобразования строки в $F[$i] в число, а затем печатает это число с printf(). Детальность можно уменьшить (это равно Perl: есть больше, чем один способ сделать это, или TMTOWTDI - tim-toady) с помощью:

$ echo '00 C9 28 13 A0 FF 01' |
> perl -na -e 'foreach my $i (@F) { printf(" %d", hex $i); } printf "\n";'
 0 201 40 19 160 255 1
$

Тот же результат, меньше кода. Там могут быть более сокращенные методы; это достаточно компактно, не будучи полностью неразборчивым.

1 голос
/ 07 февраля 2012

\ 1.проверьте, установлена ​​ли в вашей системе команда unbuffer

    which unbuffer

(обычно системы, использующие bash, основаны на Linux и имеют unbuffer в наличии)

\ 2.Если да,

    unbuffer myProgram | myScript

изменить

Как вы показали нам свой сценарий оболочки как

#!/bin/bash
echo $0
echo $#
echo $1

Пожалуйста, помните, что значения выechoing, $0, $#, $1 - это позиционные параметры для bash , связанные с аргументами командной строки .Обычно параметры или имена файлов для обработки.

Чтобы напечатать всю строку, количество полей в строке и значение первой строки, awk является идеальным решением этой проблемы.

Попробуйте изменить свой сценарий на

cat myScript.awk
#!/bin/awk -f
{ 
   print $0
   print $NF
   print $1
}

chmod 755 myScript.awk

Хмм .. Когда вы видите ^Z, чтобы остановить ввод, вы увидите, что вы используете Windows или вы используете bash под Cygwin?

Надеюсь, это поможет.

0 голосов
/ 07 февраля 2012

Это может быть проблема буферизации.GNU Coreutils поставляется с инструментом под названием stdbuf.Если он доступен в вашей системе, попробуйте выполнить:

stdbuf -o0 program | stdbuf -i0 script
...