You could output a NUL to stdout, stderr or receive it from stdin.
Any "internal" capture and (almost) any use of a NUL is a problem.
You can emit a NUL to stdout:
$ printf 'a\0b' | sed -n l
a\000b$
Or:
$ printf 'a\0b' | cat -A
a^@b
And to a file also:
$ printf 'a\0b' >outfile
And exactly that works in scripts as well.
eval
The problem with your first script is that it is using eval:
$ cmd=(printf 'a\0b\n')
$ echo "${cmd[@]}"
printf a\0b\n
$ eval echo "${cmd[@]}"
printf a0bn
In the second loop tru the shell line parsing backslashes were removed.
Just don't use eval:
$ "${cmd[@]}"| sed -n l
a\000b$
expansions
That goes to prove that both (the builtin) printf and stdout are able to use NULs.
But this fails:
$ printf '%s\n' "$(printf 'a\0b')" | cat -A
bash: warning: command substitution: ignored null byte in input
ab$
There is even (in bash 4.4+) a warning message.
In short, the shell (most shells) use C-strings internally, a C-string ends in the first NUL. Some shells cut at the first NUL in a "command expansion".
$ ksh -c 'echo $(printf "a\0b\n")|sed -n l' # also yash
a$
Some remove the NUL
$ bash -c 'echo $(printf "a\0b\n")|sed -n l'
ab$
And some even change the NUL to an space:
$ zsh -c 'echo $(printf "a\0b\n")|sed -n l'
a b$
Similar problems happen with assignments to variables.
encode
Yes, the answer you link to use uuencode to encode (and decode) the file content.
A simpler approach seems to be to use xxd (which can reverse octal dumps):
FILE="$(mktemp)"
printf "a\0b\n" > "$FILE"
S=$(xxd -p "$FILE")
xxd -r -p <(printf '%s' "$S") | xxd -p
rm "$FILE"
printf '%s' "$S"the other in your question is unsafe to the contents of$S. – Nov 21 '18 at 00:09printfis designed to have format and the string separated. When usingprintfwithout an explicit format the string could be modified by any of the escapes that also afect the commandecho. Read this and entry 2. in here for more details. – Nov 21 '18 at 03:20