4

我并不是要阻止 sed 进行块缓冲!我希望它甚至没有行缓冲区。

我不确定这是否可能。

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

可以进行一个思想实验:给定一个简单的 sed 命令,例如s/abc/zzz/g,向 sed 发送输入流123ab意味着sed 充其量可以提供超过标准输出的字符123,因为它还不知道ac是否会到达并导致结果string to be 123zzz,而任何其他字符都会让它准确打印进来的内容(如果你愿意的话,允许它“赶上”)。所以在某种程度上很明显为什么cat会立即响应;它负担得起。

所以当然这就是它在理想世界中sed的工作方式,在这个世界中,作者实际上关心这种用例。

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

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

我是索尔吗?我应该只是用我想要的功能逐步实现我的 Perl 代码,还是有机会通过某种配置获得这种神奇的美味功能?

有关我为什么想要这个的更多详细信息,请参阅我的另一个问题。

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

4

2 回答 2

3

有一个工具可以将输入流与多个正则表达式并行匹配,并在确定匹配后立即执行。这不是 sed。是莱克斯。或者 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
于 2013-05-29T20:47:12.630 回答
1

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

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

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

'/pattern/{H}'

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

'/pattern/{p}'

如果你觉得很有趣,你甚至可以嵌套这些条件块。

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

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

于 2013-05-29T18:27:53.613 回答