0

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?

5
  • 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
  • 4
    Very related: Why is printf better than echo? – Kusalananda Oct 6 '19 at 21:12
1

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:

1
2

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.

9
  • 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
  • 1
    @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
  • 1
    @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
0

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
1
  • 1
    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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.