将每个stdout行传递给windows上的命令

时间:2015-02-24 07:04:26

标签: windows batch-file pipe xargs tshark

我可以/如何将命令输出的每行传输到另一个命令(在Windows上)

例如,我有tshark输出:

1   0.000000 1.1.1.1 -> 1.1.1.2 TLSv1.2 85 Application Data
2   0.000726 1.1.1.2 -> 1.1.1.1 TLSv1.2 89 Application Data
3   0.064803 1.1.1.3 -> 1.1.1.2 TLSv1 155 Application Data
4   0.155403 1.1.1.1 -> 1.1.1.2 TCP 60 443â┼'62745 [ACK] Seq=32 Ack=36 Win=374 Len=0
5   0.268586 1.1.1.2 -> 1.1.1.3 TCP 54 56149â┼'443 [ACK] Seq=1 Ack=102 Win=63331 Len=0
6   0.730557 1.1.1.2 -> 1.1.1.4 UDP 45 Source port: 46586  Destination port: 52531
7   1.069927  1.1.1.5 -> 1.1.1.2 TCP 60 40020â┼'50293 [PSH, ACK] Seq=1 Ack=1 Win=136 Len=3
8   1.179893 fe00::dd00:9f00:dd00:1e00 -> ff00::c      SSDP 208 M-SEARCH * HTTP/1.1
9   1.269580 1.1.1.2 -> 1.1.1.5  TCP 54 50293â┼'40020 [ACK] Seq=1 Ack=4 Win=16130 Len=0

我想在每一行执行my-prog.bat,例如:

my-prog.exe   1   0.000000 1.1.1.1 -> 1.1.1.2 TLSv1.2 85 Application Data
my-prog.exe   2   0.000726 1.1.1.2 -> 1.1.1.1 TLSv1.2 89 Application Data
my-prog.exe   3   0.064803 1.1.1.3 -> 1.1.1.2 TLSv1 155 Application Data
my-prog.exe   4   0.155403 1.1.1.1 -> 1.1.1.2 TCP 60 443â┼'62745 [ACK] Seq=32 Ack=36 Win=374 Len=0
my-prog.exe   5   0.268586 1.1.1.2 -> 1.1.1.3 TCP 54 56149â┼'443 [ACK] Seq=1 Ack=102 Win=63331 Len=0
my-prog.exe   6   0.730557 1.1.1.2 -> 1.1.1.4 UDP 45 Source port: 46586  Destination port: 52531
my-prog.exe   7   1.069927  1.1.1.5 -> 1.1.1.2 TCP 60 40020â┼'50293 [PSH, ACK] Seq=1 Ack=1 Win=136 Len=3
my-prog.exe   8   1.179893 fe00::dd00:9f00:dd00:1e00 -> ff00::c      SSDP 208 M-SEARCH * HTTP/1.1
my-prog.exe   9   1.269580 1.1.1.2 -> 1.1.1.5  TCP 54 50293â┼'40020 [ACK] Seq=1 Ack=4 Win=16130 Len=0

我的my-prog.bat只是echo %TIME% %* >> test.txt

我尝试过一些事情(使用GnuWin xargs):

tshark | xargs my-prog.bat
tshark | xargs -n1 my-prog.bat

但我得到的最好的是将%*输出到文件中。 (my-prog.bat test按预期工作,并将test追加到文件中

(注意tshark将继续运行,直到按下CTRL + C)

2 个答案:

答案 0 :(得分:2)

首先验证tshark将其输出发送到stdout。如果你运行tshark >nul并且没有输出,那么确实使用了stdout,一切都很好。

如果您仍然看到输出,请使用tshark 2>nul尝试使用stderr。如果这消除了输出,则必须使用tshark 2>&1将stderr重定向到stdout。

如果以上两种方法都没有消除屏幕上的输出,那么你就不走运了。

现在,您希望将输出通过管道传输到批处理脚本,该脚本将为每行输出添加时间戳前缀。有许多并发症:

  • 输出包含>字符,当您调用批处理脚本时,该字符被解释为重定向操作。需要引用或转义违规字符。逃避是一种痛苦,引用会为你的最终输出添加不需要的引号。

  • 您需要按<Ctrl-C>来终止tshark进程,但是会终止管道的两侧,如果要终止批处理脚本,右侧会提示,但是没有更多输入 - 它挂起

在我的原始答案中,我认为你可以消除管道并通过FOR / F处理线路。但是FOR / F在命令完成之前不会开始迭代,因此无法工作。

我提出的最佳解决方案是在管道的右侧使用JScript(或VBS可以工作)来添加时间戳前缀。

假设您的左侧从未提示输入而不发出新行,那么您可以使用:

<强> addTS.js

while( !WScript.StdIn.AtEndOfStream ) {
  var time = new Date;
  WScript.StdOut.WriteLine(   zpad(time.getHours(),2) + ":"
                            + zpad(time.getMinutes(),2) + ":"
                            + zpad(time.getSeconds(),2) + '.'
                            + zpad(time.getMilliseconds(),3) + "  "
                            + WScript.StdIn.ReadLine()
                          );
}

function zpad(num, size) {
  var s = "000" + num;
  return s.substr(s.length-size);
}

<强> 用法:

tshark|cscript //nologo addTS.js

如果您的左侧在没有发出新行的情况下要求输入,那么在您提供输入之前,您将无法看到提示。这并不好用。所以这是addTS.js的修改版本,它可以单独读取和写入每个字符:

var time, chr, newLine=true;
while( !WScript.StdIn.AtEndOfStream ) {
  chr=WScript.StdIn.Read(1);
  if (newLine) {
    time = new Date();
    WScript.StdOut.Write(   zpad(time.getHours(),2) + ":"
                          + zpad(time.getMinutes(),2) + ":"
                          + zpad(time.getSeconds(),2) + '.'
                          + zpad(time.getMilliseconds(),3) + "  "
                        );
    newLine=false;
  }
  WScript.StdOut.Write(chr);
  newLine=(chr=='\n');
}

function zpad(num, size) {
  var s = "000" + num;
  return s.substr(s.length-size);
}

答案 1 :(得分:1)

你为什么不这样做:

for /f "delims=" %%a in ('tshark') do (my-prog.bat %%a)

这正是你想要的。

注意:这适用于批处理文件。如果您想直接在命令提示符中执行此操作,则必须将%%a替换为%a

替代解决方案

我刚刚注意到,最终结果是有一个日志文件,其中包含来自tshark的数据。如果是这种情况你可以:

tshark > test.txt

与调用my-prog.bat的结果相同,它也会逐行执行,因此您可以无限期地运行它。我已经在我的计算机上测试了它(在dir /s > test.txt中运行C:并且当它运行type test.txt时,虽然命令还没有完成,但已经有线路了。“ / p>