我有一个写入fd3的程序,我想用grep和sed处理这些数据。以下是代码到目前为止的样子:
exec 3> >(grep "good:"|sed -u "s/.*:\(.*\)/I got: \1/")
echo "bad:data1">&3
echo "good:data2">&3
在我做
之前没有输出任何内容 exec 3>&-
然后,我想要的一切终于按照我的预期到达:
I got: data2
如果我只使用grep或者只使用sed,它似乎立即回复,但混合它们似乎会导致某种缓冲。如何从fd3立即获得输出?
答案 0 :(得分:8)
我想我找到了它。出于某种原因,grep不会自动进行行缓冲。我向--line-buffered
添加了grep
选项,现在它立即响应。
答案 1 :(得分:4)
阻止sed
缓冲的另一种方法是通过the s2p sed-to-Perl translator运行它并插入一个指令让命令缓冲,也许就像
BEGIN { $| = 1 }
这样做的另一个原因是它为您提供了更方便的符号来表示ERE而不是反斜杠 - 令人讨厌的传统BRE。您还可以获得完整的Unicode属性,这通常很重要。
但是你不需要翻译器来完成这么简单的sed
命令。而且您也不需要grep
和sed
。这些都有效:
perl -nle 'BEGIN{$|=1} if (/good:/) { s/.*:(.*)/I got: $1/; print }'
perl -nle 'BEGIN{$|=1} next unless /good:/; s/.*:(.*)/I got: $1/; print'
perl -nle 'BEGIN{$|=1} next unless /good:/; s/.*:/I got: /; print'
现在,您还可以访问最小量词*?
,+?
,??
,{N,}?
和{N,M}?
。这些现在允许.*?
或\S+?
或[\p{Pd}.]??
之类的内容,这可能更合适。
答案 2 :(得分:3)
您可以将grep
合并到sed
中,如下所示:
exec 3> >(sed -une '/^good:/s//I got: /p')
echo "bad:data1">&3
echo "good:data2">&3
解压缩一下:您可以在任何sed命令之前放置正则表达式(像往常一样在斜杠之间),这使得它只应用于与该正则表达式匹配的行。如果s
命令的第一个regexp参数是空字符串(s//whatever/
),那么它将重用匹配的最后一个正则表达式,在这种情况下是前缀,这样就可以节省自己重复的次数。最后,-n
选项告诉sed只打印专门告诉打印的内容,/p
命令的s
后缀告诉它打印替换结果。 / p>
-e
选项不是绝对必要的,但它是好的样式,它只是意味着“下一个参数是sed脚本,而不是文件名”。
除非你需要在那里替换一个shell变量,否则总是将sed脚本放在单引号中,即使这样我也会将所有但 shell变量放在单引号中(当然shell变量是,双引号)。你可以避免一堆反斜杠相关的悲伤。
答案 3 :(得分:2)
在Mac上,brew install coreutils
并使用gstdbuf来控制grep和sed的缓冲。
答案 4 :(得分:2)
你只需要告诉 grep 和 sed 不要缓冲行:
grep --line-buffered
和
sed -u
答案 5 :(得分:0)
Turn off buffering in pipe似乎是最简单,最通用的答案。使用stdbuf(coreutils):
exec 3> >(stdbuf -oL grep "good:" | sed -u "s/.*:\(.*\)/I got: \1/")
echo "bad:data1">&3
echo "good:data2">&3
I got: data2
缓冲还有其他依赖性,例如,取决于mawk或gawk读取此管道:
exec 3> >(stdbuf -oL grep "good:" | awk '{ sub(".*:", "I got: "); print }')
在这种情况下,mawk会保留输入,而gawk不会保留输入。