How to disable word splitting during command substitution

command-substitutionzsh

How can I disable word-splitting during command substitution? Here's a simplified example of the problem:

 4:00PM /Users/paymahn/Downloads
 ❯❯❯ cat test.txt
hello\nworld
 4:00PM /Users/paymahn/Downloads
 ❯❯❯ echo $(cat test.txt )
hello
world
 4:00PM /Users/paymahn/Downloads
 ❯❯❯ echo "$(cat test.txt )"
hello
world
 4:01PM /Users/paymahn/Downloads
 ❯❯❯ echo "$(cat "test.txt" )"
hello
world

What I want is for echo $(cat test.txt) (or some variant of that which includes command subsitution) to output hello\nworld.

I found https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html which says at the bottom If the substitution appears within double quotes, word splitting and filename expansion are not performed on the results. but I can't seem to make sense of that. I would have thought that one of the examples I already tried conformed to that rule but I guess not.

Best Answer

Having a literal \n get changed to a newline isn't about word splitting, but echo processing the backslash. Some versions of echo do that, some don't... Bash's echo doesn't process backslash-escapes by default (without the -e flag or xpg_echo option), but e.g. dash's and Zsh's versions of echo do.

$ cat test.txt 
hello\nworld
$ bash -c 'echo "$(cat test.txt)"'
hello\nworld
$ zsh -c 'echo "$(cat test.txt)"'
hello
world

Use printf instead:

$ bash -c 'printf "%s\n" "$(cat test.txt)"'
hello\nworld
$ zsh -c 'printf "%s\n" "$(cat test.txt)"'
hello\nworld

See also: Why is printf better than echo?

Regardless of that, you should put the quotes around the command substitution to prevent word splitting and globbing in sh-like shells. (zsh only does word splitting (not globbing) upon command substitution (not upon parameter or arithmetic expansions) except in sh-mode.)

Related Question