搜索三个连续的换行符?

搜索三个连续的换行符?

我知道可以使用挤压多个空白行cat -s(并且可以使用挤压所有空白行tr -s '\n'),但我很好奇如何搜索对于输入流中的这种情况。

我以为这样stream-of-input | grep -qz $'\n\n\n'就可以了,但事实并非如此。

有没有办法用简单的工具进行这种搜索?

换句话说,读取输入,如果三个连续字节是换行符,则以零状态退出;如果到达 EOF 而没有找到三个连续换行符,则以非零状态退出。

答案1

您可以使用tr将流转换为可以正常 grep 的流:

stream | tr 'x\n' '\0x' | grep -qz xxx

这会将所有x字节转换为空字节,并将所有换行字节转换为xs,这些字节可以像往常一样被 grep 出来。也就是说,它沿着路径 linefeed -> x -> null 移动一步,因此三个换行符的序列现在将成为三个xs 的序列,并且不会x出现其他字节(它们将成为 的 null 终止行grep) 。


这有效与 POSIXtr,但是grep -z是一个扩展。你可能不需要它 - 这里不需要分离行为 - 并且大多数greps 将处理二进制数据,但是POSIXgrep仅需要处理文本文件所以你会以某种方式依赖扩展。

如果您的真实数据是文本文件,或者只是不依赖于二进制安全行为,那么您可能可以生存

stream | tr 'x\n' '\nx' | grep -q xxx

- 也就是说,只是交换两个字节。这是几乎POSIX 兼容,但可能在实践中几乎任何地方都可以工作(问题是最后一行不会被正确终止,所以它不是一个文本文件,所以grep不严格要求接受它)。

任何一种情况下的一个可能的问题是,没有现有字节的文件将被视为一个很长的行,这可能超出您的实现将处理的x限制。grep选择另一个预期常见的字节可能会解决这个问题。

我很惊讶你原来的grep -qz $'\n\n\n'命令不起作用,但它有一个错误-积极的对我来说有问题 - 它似乎表现得像grep -qz ''并且总是匹配。我不知道为什么会这样。

答案2

lex( 或flex) 可以处理这个问题,例如以下内容保存到文件中,tresn.l并带有额外的规则,主要是为了防止默认输出到标准输出(您可能想要那个?)

%%
\n\n\n  { exit(0); }
<<EOF>> { exit(1); }
\n\n    { ; }
\n      { ; }
.       { ; }
%%

使用隐式规则进行编译make并引入libfl*

$ CFLAGS=-lfl make tresn
lex  -o lex.tresn.c tresn.l
cc -lfl   -o tresn lex.tresn.c  -ll
rm -f lex.tresn.c
$ printf "\n\n" | ./tresn ; echo $?
1
$ printf "\n\n\n" | ./tresn ; echo $?
0

在某些系统上,您可能需要添加-L/opt/local/libCFLAGS隐藏LDFLAGSlibfl*供应商编译空间之外的某些端口或软件包系统下。

相关内容