【问题标题】:How do I grep or sed in a continuous stream of characters?如何在连续的字符流中 grep 或 sed?
【发布时间】:2017-04-27 13:37:47
【问题描述】:

我有一个程序可以输出一些文本,然后是连续的字符流:

perl -E '$|=1;print "OUT\n";print "A" and sleep 1 for 1..10'

我想在输出中看到“A”后立即退出该程序,我尝试了:

grep -m 1 A <(perl -E '$|=1;print "OUT\n";print "A" and sleep 1 for 1..10')

但是,在 perl 程序退出之前,grep 似乎看不到“A”。

我也尝试过 sed,但没有成功;

sed /A/q <(perl -E '$|=1;print "OUT\n";print "A" and sleep 1 for 1..10')

有什么办法可以解决这个问题吗?

【问题讨论】:

    标签: linux shell sed grep buffer


    【解决方案1】:

    这里的问题是grepsed 都会逐行处理它们的输入,除非另有说明。一种解决方法是插入换行符,例如与 coreutils fold:

    grep -m 1 A \
      <(perl -E '$|=1;print "OUT\n";print "A" and sleep 1 for 1..10' | fold -w1)
    

    但是由于管道缓冲,这仍然存在问题。您可以使用 coreutils stdbuf 禁用此功能:

    grep -m 1 A \
      <(perl -E '$|=1;print "OUT\n";print "A" and sleep 1 for 1..10' |
        stdbuf -o0 fold -w1)
    

    另一种选择是使用dd,例如:

    perl -E '$|=1;print "OUT\n";print "A" and sleep 1 for 1..10' |
    while :; do
      c=$(dd bs=1 count=1 status=none)
      if [[ "$c" == "A" ]]; then
        break
      else
        : Do something else
      fi
    done
    

    【讨论】:

    • 不,grep(1)sed(1) 在输入不是来自终端时使用大缓冲区读取,因此您不能假设读取整行,而是读取大块数据,这会导致问题更糟。
    • @LuisColorado:当它们位于管道末端时,它们使用行缓冲。比较例如:seq 3 | while read; do echo $REPLY; sleep 1; done | grep .seq 3 | while read; do echo $REPLY; sleep 1; done | grep . | cat
    • 不,他们逐行处理输入,但他们读取文件系统信息指示的块(每次一个完整的磁盘块)。相信我,或者查看程序源。目标是高效,逐行读取不会带来任何改进(这在管道中确实是不可能的,因为没有字符处理——如在设备驱动程序中——在内核中完成以在每一端获取输入行标记,因此无法进行行缓冲)
    • @LuisColorado:我明白你的意思。我的解释是基于它对用户的显示方式,而不涉及太多细节。我根据你的cmets做了一些调整。
    猜你喜欢
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-19
    • 1970-01-01
    相关资源
    最近更新 更多