You can use tr
to transform the stream into one you can grep normally:
stream | tr 'x\n' '\0x' | grep -qz xxx
This turns all x
bytes into null bytes, and all linefeed bytes into x
s, which can be grepped out as usual. That is, it moves one step along the path linefeed -> x -> null, so a sequence of three linefeeds will now be a sequence of three x
s, and no other x
bytes will occur (they will have become nulls terminating lines for the grep
).
This works with POSIX tr
, but grep -z
is an extension. You may not need it - the separation behaviour isn't required here - and most grep
s will handle binary data, but POSIX grep
is only required to work on text files so you're going to be depending on an extension one way or another.
If your real data is a text file, or just doesn't depend on binary-safe behaviour, you can probably survive on just
stream | tr 'x\n' '\nx' | grep -q xxx
- that is, just swapping the two bytes. This is nearly POSIX-compatible, but will likely work in practice just about anywhere (the issue is that the final line won't be terminated correctly, so it's not a text file, so grep
isn't strictly required to accept it).
One possible issue in either case is that a file with no existing x
bytes will be considered as one very long line, which may exceed the limits your grep
implementation will handle. Choosing another expected-to-be-common byte may work around that.
I was surprised that your original grep -qz $'\n\n\n'
command didn't work, but it had a false-positive problem for me - it seemed to behave like grep -qz ''
and always matched. I'm not sure why that is.
grep -Pzq '\n\n\n'
seems to work... not sure the whys and wherefores – steeldriver Jan 08 '19 at 03:34