【问题标题】:Pipe each stdout line to a comand on windows将每个标准输出行通过管道传输到 Windows 上的命令
【发布时间】:2015-04-25 17:30:41
【问题描述】:

我可以/如何将命令的每一行输出传送到另一个命令(在 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)

【问题讨论】:

    标签: windows batch-file pipe xargs tshark


    【解决方案1】:

    首先验证 tshark 是否将其输出发送到标准输出。如果你运行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);
    }
    

    【讨论】:

    • 嗯,好像没用。 tshark > nul 按预期工作。但是您的中间示例似乎仅在按下 ctrl+c 之后(而不是在每一行之后)写入。使用第一个/最后一个示例根本不起作用。
    • @Petah - 我忘记了 FOR /F 在命令完成之前不会开始迭代输出行,所以我原来的解决方案无法工作。我已经用应该可以工作的 JScript 解决方案更新了我的答案。
    【解决方案2】:

    你为什么不这样做:

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

    这正是你想要的。

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

    替代解决方案

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

    tshark > test.txt
    

    这与调用my-prog.bat 的结果相同,它也会逐行执行,因此您可以让它无限期地运行。我已经在我的计算机上对其进行了测试(通过在C: 中运行dir /s > test.txt 并在它运行时type test.txt 并且虽然命令尚未完成但其中已经有行)。

    【讨论】:

    • 嗯,这似乎适用于dir,但这是一个示例命令,我使用的是tshark(对此感到抱歉)。我会改写我的问题。
    • @Petah 试试我的新解决方案
    • 不幸的是,它似乎没有执行my-prog.bat 命令。没有任何内容输出到test.txt
    • 我提出了一个替代解决方案,第一个问题可能与Ctrl-C 的事情有关
    • 我可以看到你要去哪里,但我想实时地逐行调用my-prog.bat,而不是在tshark结束之后(即让tshark无限期运行)
    猜你喜欢
    • 1970-01-01
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    • 2020-11-02
    相关资源
    最近更新 更多