我知道可以使用挤压多个空白行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
字节转换为空字节,并将所有换行字节转换为x
s,这些字节可以像往常一样被 grep 出来。也就是说,它沿着路径 linefeed -> x -> null 移动一步,因此三个换行符的序列现在将成为三个x
s 的序列,并且不会x
出现其他字节(它们将成为 的 null 终止行grep
) 。
这有效与 POSIXtr
,但是grep -z
是一个扩展。你可能不需要它 - 这里不需要分离行为 - 并且大多数grep
s 将处理二进制数据,但是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/lib
或CFLAGS
隐藏LDFLAGS
在libfl*
供应商编译空间之外的某些端口或软件包系统下。