Context

I have a file my-cmd:

echo '<some data...>\\<some other data...>'


Basically, I want to redirect the output of this command to a text file:

./my-cmd > file.txt


Question

My problem is that > always replaces any occurrence of \\ to \ in file.txt.

How can I prevent this behaviour?

• Why do you need echo "$( ... )" at all? why can't you redirect the output directly my-cmd > file.txt? – steeldriver Oct 6 '19 at 19:26 • @steeldriver You got a point, I simplified my question. However, I still have the issue of \\ transformed into \ when redirected with > – Louis-Jacob Lebel Oct 6 '19 at 19:41 • How does my-cmd produce its output? – NickD Oct 6 '19 at 20:25 • @NickD Does it matter? Currently it echo '<data>''s it (with single quotes). – Louis-Jacob Lebel Oct 6 '19 at 20:28 • Very related: Why is printf better than echo? – Kusalananda Oct 6 '19 at 21:12 3 Answers echo is a non-portable command whose behaviour varies across implementations, versions, their compile-time and runtime option and the environment. In particular, you shouldn't use it if its first argument may start with - (though zsh's builtin echo is one of the rare implementations that can work around that) or if any argument contains backslash characters. Specifically with the zsh echo builtin implementation, \ sequences (like \n, \c, \61, \\...) are expanded (as required by POSIX+XSI, while POSIX without XSI leaves the behaviour unspecified) unless the bsdecho option is enabled (disabled by default on most deployments), while for bash they are only expanded when the xpg_echo is enabled (disabled by default on most deployments). Both zsh and bash echos support a (non-standard) -E option to disable the expansions (not supported by bash's if both the xpg_echo and posix options are enabled though). Here, even though you could do: echo -E '<some data...>\\<some other data...>' > file  Which would work OK in zsh and in most deployments of bash, it would be much better to use the standard printf command: printf '%s\n' '<some data...>\\<some other data...>' > file  Whose behaviour in that case is completely specified by POSIX and works the same across all implementations. Note that the printf utility is a POSIX invention. Long before POSIX, the Korn shell's answer to that non-portable echo mess-up was a new print builtin and its -r option to not expand \x sequences and a - to mark the end of options. zsh does have a Korn-like print builtin, but bash doesn't. In ksh and zsh, you can also do: print -r - "$var"


To print arbitrary data as-is.

More details at:

If my-cmd does something like this:

echo "abc\\def"


the output will be abc\def: the backslash is interpreted as an escape character inside double quotes. OTOH, it is treated as a literal backslash inside single quotes:

echo 'abc\\def'


will produce abc\\def as output.

EDIT: This was tested with bash. The OP has since changed the tag to "zsh", so this does not answer his question. If the moderators think it's now irrelevant, I will delete it.

• When sent to a text file: echo 'abc\\def' > file.txt, then file.txt is fed with abc\def – Louis-Jacob Lebel Oct 6 '19 at 20:29
• Not here: $echo 'abc\\def' > foo.txt, $cat foo.txt output: abc\\def – NickD Oct 6 '19 at 20:32
• Well, I just tried it right now, and I cannot come to the same conclusion as you. Thought I'm using zsh: does zsh treat differently >? – Louis-Jacob Lebel Oct 6 '19 at 20:35
• @Louis-JacobLebel You're not using /bin/echo, but zsh's built-in echo with enabled escape sequences. Use echo -E '…' to disable the interpretation of escape sequences. It has nothing to do with redirection. – Freddy Oct 6 '19 at 20:50
• @Kusalananda You are right, I forgot that zsh and bash were two different things. I changed the bash tag to zsh. Adding how my-cmd prints data to the question too. – Louis-Jacob Lebel Oct 6 '19 at 21:25

According to what Freddy said in the comments of NickD's answer, my-cmd should be:

/bin/echo -E '<some data...>\\<some other data...>'


So basically, because I'm under zsh and not bash, by default I'm using an echo command that treats backslash characters specially. I had to tell zsh that I want to use the /bin/echo command instead, and also had to call it with its -E option.

Here's what man echo says about the -E option:

   -E     disable interpretation of backslash escapes

• zsh's echo does support -E as well, no need for /bin/echo (which on many systems doesn't support -E). It also supports print -r like ksh and the POSIX printf '%s\n' .... bash also expands \ sequences (as required by POSIX+XSI) when in compliance mode. The correct answer here is to **not** use echo, but printf instead. – Stéphane Chazelas Oct 8 '19 at 6:12