grep --null
A few days ago a commit within OpenBSD caught my attention: what was this thing about --null
flag in grap
?
I am an avid user of
grep
, as many of us are when dealing with scripts and files and shells, however I was not aware of the --null
feature. It turned out that GNU version of grep
already has such feature, as well as the FreeBSD version, so OpenBSD here was simply catching up.
But what is all about? Well, sometimes you have filenames with a newline at the end.
Let’s not discuss about how terrible such an idea is…
grep
without the --null
Here’s a simple example about the effects of having a newline at the end of the filename:
% cat << EOF >! "test.txt
"
Hello
World
EOF
test.c: sprintf( database, "Hello World!");
test.txt
:World
test.z:world
As you can see, the
test.txt
filename ends with a \n
newline character, so when we grep
multiple files (hence grep
has to print the matching line with the filename prefix), the name of test.txt
makes the matching line to appear on the very new line (on the other hand, test.c
works as expected).
grep --null
What is the effect of --null
option? In order to better understand it, ask grep
to give us only the list of files that do match:
% grep -i world -l test.*
test.c
test.txt
test.z
In the output there is an extra new file due to the filename that ends with a newline. Now add the
--null
flag:
% grep -i world -l --null test.*
test.ctest.txt
test.z
The extra new line has disappeared, and now only the effective newline that is part of the filename is present. This is good to feed other beasts, like
xargs
% grep -i world -l --null test.* | xargs -0 ls -s
4 test.c 4 'test.txt'$'\n' 4 test.z
that without the no-newline trick whould have been very confused in interpreting the filename:
% grep -i world -l test.* | xargs ls -s
ls: cannot access 'test.txt': No such file or directory
4 test.c 4 test.z
Why is named --null
?
C developers mindset here: it appends a NULL string terminator at the end of the filename instead of the usual \n
for a newline.
To some extent, this is the equivalent form of
print0
in find
.