With --null-data (-z), records are separated by NUL (\0), so a newline \n is ordinary data. GNU's . matches any byte except the active record separator, so under --null-data . matches \n. uu_grep's . never matches \n, so it skips the newline bytes inside a NUL-delimited record.
Found by the differential fuzzer (fuzz_grep).
Input is a single NUL-record containing a, a newline, and b (output piped through tr '\0' '/' for readability).
Rust (incorrect)
$ printf 'a\nb' | ./target/release/grep -e '.' -o --null-data | tr '\0' '/'
a/b/
# the '\n' between a and b is not matched
GNU (correct)
$ printf 'a\nb' | LC_ALL=C /usr/bin/grep -e '.' -o --null-data | tr '\0' '/'
a/
/b/
# '\n' is matched as an ordinary character
Control (no --null-data, so \n is the separator): grep -e '.' -o yields a/b/ in both — the newline is correctly excluded only when it is the record separator.
With
--null-data(-z), records are separated by NUL (\0), so a newline\nis ordinary data. GNU's.matches any byte except the active record separator, so under--null-data.matches\n.uu_grep's.never matches\n, so it skips the newline bytes inside a NUL-delimited record.Found by the differential fuzzer (
fuzz_grep).Input is a single NUL-record containing
a, a newline, andb(output piped throughtr '\0' '/'for readability).Rust (incorrect)
GNU (correct)
Control (no
--null-data, so\nis the separator):grep -e '.' -oyieldsa/b/in both — the newline is correctly excluded only when it is the record separator.