如何在连续的字符流中进行grep或sed ?

时间:2022-11-23 14:05:22

I have a program that output some text and then a continuous stream of characters:

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

I want to exit this program as soon as "A" is seen in the output and I tried:

我想在输出中看到“A”后就退出这个程序,我尝试:

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

However, it seems like grep doesn't see the "A"s until the perl program exits.

然而,grep似乎直到perl程序退出才看到“A”。

I also tried with sed with no luck;

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

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

Any ideas how I can solve this?

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

1 个解决方案

#1


2  

The issue here is that both grep and sed process their input linewise unless they are told otherwise. One workaround is to insert newlines, e.g. with coreutils fold:

这里的问题是,grep和sed都以线性方式处理它们的输入,除非被告知不这样做。一种方法是插入换行,例如用coreutils折叠:

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

But this still has issues because of pipe-buffering. You can disable this with coreutils stdbuf:

但由于管道缓冲,这仍然存在问题。你可以禁用coreutils stdbuf:

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

Another alternative is to use dd, e.g.:

另一种选择是使用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

#1


2  

The issue here is that both grep and sed process their input linewise unless they are told otherwise. One workaround is to insert newlines, e.g. with coreutils fold:

这里的问题是,grep和sed都以线性方式处理它们的输入,除非被告知不这样做。一种方法是插入换行,例如用coreutils折叠:

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

But this still has issues because of pipe-buffering. You can disable this with coreutils stdbuf:

但由于管道缓冲,这仍然存在问题。你可以禁用coreutils stdbuf:

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

Another alternative is to use dd, e.g.:

另一种选择是使用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