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"