7

Can \0 be used on the command line?

Background

For testing corner cases in GNU Parallel I was curious whether all characters were correctly quoted on the command line. Most of them are:

perl -e 'print pack ("c*",1..255,10)' | parallel -k echo | md5sum
d03484ca75b3e38be411198d66bf4611  -
perl -e 'print pack ("c*",1..255,10)' | md5sum
d03484ca75b3e38be411198d66bf4611  -

But \0 seems to be tricky (here illustrated with A\0B\n):

perl -e 'print pack ("c*",65,0,66,10)' | wc -c
4 (A\0B\n)
perl -e 'print pack ("c*",65,0,66,10)' | parallel echo | wc -c
2 (A\n)
perl -e 'print pack ("c*",65,0,66,10)' | parallel --dry-run echo | wc -c
9 (echo A\0B\n)
perl -e 'print "echo ",pack ("c*",65,0,66,10)' | bash | wc -c
3 (AB\n)

I can sort of justify the second example: \0 may be interpreted as EOS, but then that also ought to be the case in example 4. Example 3 stresses that GNU Parallel does not see \0 as EOS, but passes it on to bash.

Can you explain what is going on—especially case 4 puzzles me.

And more importantly:

Is there a way to quote \0 on the command line so that e.g. echo will see it?

Ole Tange
  • 35,514

1 Answers1

9

When executing a command, the list of arguments is a list of pointers to NUL terminated strings passed to the execve() system call (just like the environment variables which is the other list of NUL-terminated strings passed to execve()).

As a result, arguments and environment variables of executed commands cannot contain the NUL character.

Exception to that are built-ins and functions in the zsh shell whose arguments may can contain anything (those are built-in so the execve() system call is not involved).

You can pass data with NUL characters via stdin (or any other file descriptor) or in any type of file. Or some command understand some form of encoding.

For instance, UNIX conformant echo implementations understand \0 (the two characters backslash and zero) as meaning the NUL character. Some other implementations do that only when passed the -e flag.

So:

echo '\0'

or:

echo -e '\0'

May cause echo to output the NUL character followed by the LF character.

With zsh,

echo $'\0'

passes the NUL character to the echo built-in.

/bin/echo $'\0'

Would not work because /bin/echo is executed, so its argument cannot contain the NUL character.

As to your point 4 question. It's just that bash ignores those NUL characters. Some other shells behave differently.

$ printf 'e\0cho a\0b\n' | bash |& sed -n l
ab$
$ printf 'e\0cho a\0b\n' | ksh |& sed -n l
ksh: syntax error at line 1: `zero byte' unexpected$
$ printf 'e\0cho a\0b\n' | zsh |& sed -n l
zsh: command not found: e$
$ printf 'e\0cho a\0b\n' | rc |& sed -n l
line 1: warning: null character ignored$
line 1: warning: null character ignored$
ab$