将stdout重定向到脚本,因此可以将其解析,然后发送到stdout

时间:2012-02-06 23:35:26

标签: bash redirect stdout pipe

我有一个(java)程序,每5秒钟向stdout输出一行十六进制数,直到用户终止该程序。

我想将该输出重定向到bash脚本,以便我可以将每个十六进制数独立转换为十进制数,然后将解析后的行打印到stdout。

我尝试使用myProgram | myScript但是在打印任何行之前都进行了管道处理,然后没有继续听stdout。然后我尝试了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 个答案:

答案 0 :(得分:1)

\ 1。检查您的系统是否安装了unbuffer命令

    which unbuffer

(通常使用bash的系统是基于Linux的,并且unbuffer可用)

\ 2。如果是的话,

    unbuffer myProgram | myScript

修改

正如您向我们展示了您的shell脚本

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

请注意,您回显的值$0, $#, $1是与命令行参数相关的bash 的位置参数。通常用于处理的选项或文件名。

要打印整行,行上的字段数和第一行的值,awk是解决此问题的完美解决方案。

尝试将脚本更改为

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

chmod 755 myScript.awk

嗯..看到^Z停止输入告诉我你正在使用Windows,或者你在Cygwin下使用bash?

我希望这会有所帮助。

答案 1 :(得分:1)

诊断

当你像这样使用这个脚本时:

java javaprog | myScript

myScript包含:

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

然后脚本的输出将是myScript的名称(echo $0),它从echo $#传递的参数数量(0),以及第一个参数(来自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";}'

这表示'对于每一行(因为在开括号之前没有模式)',对于每个字段1..NF执行',将字段转换为带有0x前缀的显式十六进制字符串并添加0,然后将值打印为十进制数字(信任awk将字符串(如“0xC9”)转换为数字)。

使用Perl

不幸的是,一点测试显示这不起作用;问题是x获得的值不是0。所以,...时间以awk - 仿真模式回归Perl:

$ 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]中的字符串转换为数字,然后使用{{1打印该数字}}。可以减少详细程度( Perl:有多种方法可以做到,或TMTOWTDI - tim-toady):

printf()

结果相同,代码更少。可能有更多缩写技术;这个很紧凑,没有完全难以理解。

答案 2 :(得分:0)

这可能是一个缓冲问题。 GNU Coreutils附带了一个名为stdbuf的工具。如果您的系统上有,请尝试运行:

stdbuf -o0 program | stdbuf -i0 script