使sed不按行缓冲

时间:2013-04-20 05:34:46

标签: perl unix io sed stdio

我并不是想阻止sed进行块缓冲!我希望得到它甚至不行缓冲。

我不确定这是否甚至可能。

基本上,sed的行为与cat的行为在从原始伪终端与它们进行交互时会有很大差异:cat会立即吐出插入的字符它通过STDIN接收它们,而sed即使在原始模式下也不会。

可以执行思想实验:给定一个简单的sed命令,例如s/abc/zzz/g,将输入流发送到sed,如123ab,意味着sed 最好< / em>可以通过标准输出提供字符123,因为如果c到达并且导致结果字符串为123zzz还不知道 ,而任何其他角色都会准确地打印出来的内容(允许它“赶上”,如果你愿意的话)。所以在某种程度上,cat确实立即做出反应是显而易见的;它可以负担得起。

当然,在sed的作者真正关心这种用例的理想世界中,它是如何工作的。

我怀疑情况并非如此。实际上,通过我不那么详尽的方法,我发现sed无论什么都行缓冲(这使得它总是能够弄清楚是否打印3 z),除非你告诉它你关心的是你的正则表达式是否匹配过去/换过新行,在这种情况下它只会在提供任何输出之前缓冲整个该死的东西。

我理想的解决方案是找到一个sed,它会将已经完成解析的所有文本吐出来,而不必等到行尾才能这样做。在我上面的小例子中,它会立即回吐字符123,同时输入ab(键入),它什么也没说,直到看到c(打印zzz),或看到任何其他字符X,在这种情况下打印abX,或者打印EOF ab的情况。

我是SOL吗?我是否应该使用我想要的功能逐步实现我的Perl代码,还是仍然有可能通过某种配置获得这种神奇可口的功能?

有关我为什么要这样做的详细信息,请参阅another question of mine

因此,一个可能的解决方法是手动建立输入组,以便在调用sed之间“拆分”(或者在我的情况下,因为我已经在处理Perl脚本,perl的正则表达式替换运算符)这样我就可以手动进行冲洗了。但是这不能达到相同的响应水平,因为它需要通过表达式来思考“缓冲”发生的点,而不是让正则表达式解析器自动执行它。

2 个答案:

答案 0 :(得分:3)

有一个工具可以将输入流与多个正则表达式并行匹配,并在决定匹配时立即执行。它不是sed。这是lex。或GNU版本,flex。

为了使这个演示工作,我必须定义一个YY_INPUT宏,因为flex是默认的行缓冲输入。即使在stdio级别,甚至在“交互式”模式下没有缓冲,也有一种假设,即您不希望一次处理少于一行。

所以这可能无法移植到其他版本的lex。

%{
#include <stdio.h>

#define YY_INPUT(buf,result,max_size) \
   { \
   int c = getchar(); \
   result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
   }
%}

%%

abc  fputs("zzz", stdout); fflush(stdout);
.    fputs(yytext, stdout); fflush(stdout);

%%

int main(void)
{
  setbuf(stdin, 0);
  yylex();
}

用法:将该程序放入名为abczzz.l的文件中并运行

flex --always-interactive -o abczzz.c abczzz.l
cc abczzz.c -ll -o abczzz
for ch in a b c 1 2 3 ; do echo -n $ch ; sleep 1 ; done | ./abczzz ; echo

答案 1 :(得分:0)

你实际上可以在sed中编写整个程序。 这是一种将整个文件粘贴到编辑缓冲区的方法。我添加了-n来抑制打印和$ p所以它只会在我用我正在编辑的当前缓冲区建立的保持空间之后打印最后的缓冲区。

 sed -n 'H;$x;$p' FILENAME

您可以根据遇到的模式有条件地建立保留空间:

'/pattern/{H}'

您也可以有条件地打印缓冲区

'/pattern/{p}'

如果你感觉很好,你甚至可以嵌套这些条件块。

您可以使用`g'的组合(将保留空间复制到模式空间,从而覆盖它),然后使用s /(。)。* / \ 1 /等来获取单个字符。

我希望这至少可以提供丰富的信息。我建议你用不同的语言写一个工具。