当传递给sed或awk时,冗长的管道命令输出会挂起

4

背景

我正在进行对CI构建的更改,触发命令运行我的Xcode单元测试输出。这些测试记录了大量冗长的信息,以至于超过了4 MB的日志捕获限制,导致我的构建被终止。据我所知,没有办法使其变得不那么冗长(我想到的一个方法需要更改运行测试的命令,我正在进行中)。

我的解决方法

所以我决定聪明一点,尝试使用 sed 过滤我的输出,就像这样:

test_running_command | sed '/xctest\[/d; /^$/d'

当我在文件上运行sed命令时,它按预期过滤掉包含xctest [和空行的行。但是当我将其纳入到我的CI构建中时,我看到输出流到一定点,然后就停止了。在10分钟后,无论如何都会杀死我的CI构建,在我还没有机会达到4 MB限制之前。

问题

为什么sed会出现这种情况?

已执行的故障排除

  • I tried using awk, like so, which similarly hangs.

    test_running_command | awk '$0 !~ /xctest\[/ && $0 !~ /^$/ {print}'
    
  • I tried a command from this answer to turn on line buffering for the original command, which just hung at a different place.

    script -q /dev/null test_running_command | <sed or awk command from above>
    
  • As suggested by @CharlesDuffy in a comment, I used tee to write to file what goes into the pipe, and determined that the left side of the pipe definitely gets much further than the right. I observed (on my local machine) that while the output to the console was frozen, before_filter.txt was continuing to progress. This is the line I used:

    test_running_command | tee before.txt | sed '/xctest\[/d; /^$/d' | tee after.txt
    
  • As suggested by @LuisMuñoz in a comment, I tried using stdbuf (after installing with brew install coreutils) to disable buffering into and out of sed. I didn't see a difference in behavior. Output still froze at an arbitrary point.

    test_running_command | gstdbuf -i0 -o0 sed '/xctest\[/d; /^$/d'
    

2
你确定输出缓冲区在倒出内容后会重新填充吗? - Charles Duffy
2
一个有用的调试步骤是在两端放置“tee”:test_running_command | tee before_filter | sed ... | tee after_filter - Charles Duffy
我觉得我们可能需要更多关于你运行环境的信息......有可能你需要封装你的测试和过滤器...像这样 sh -c 'test_running_command | sed "/xctest\[/d; /^\$/d"' - Michael Back
1
这个命令对我有效:在awk之前加上stdbuf -i0 -o0,请参考这个答案 - LMC
@LuisMuñoz 我正在使用 Mac,看起来这不是一个内置命令。 - Dov
显示剩余5条评论
1个回答

1

我发现了-l标志用于sed。显然,这会打开行缓冲模式,产生所需的效果。我想知道是否由于生成的极长行导致其缓冲区溢出而出现问题。无论如何,这个命令最终有效:

 test_running_command | sed -l '/xctest\[/d; /^$/d'

作为一个侧面的注释,我曾经有一个测试在CI服务器上花费了超过10分钟的时间,由于没有日志输出,导致出现了超时。我在其外部循环中放置了一个单独的printf语句,产生了足够的日志输出,以免构建被杀死。这个printf行没有被sed命令过滤,所以这是完美的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接