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?

ljleb
  • 113

4 Answers4

3

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.

NickD
  • 2,926
  • When sent to a text file: echo 'abc\\def' > file.txt, then file.txt is fed with abc\def – ljleb Oct 06 '19 at 20:29
  • Not here: $ echo 'abc\\def' > foo.txt, $cat foo.txt output: abc\\def – NickD Oct 06 '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 >? – ljleb Oct 06 '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 06 '19 at 20:50
  • @Freddy That was it. Actually under zsh, echo -E '...' prints -E ...... but /bin/echo -E '...' works like magic! – ljleb Oct 06 '19 at 21:04
  • @Louis-JacobLebel Are you sure you're using zsh? What's the output of echo $0? – Freddy Oct 06 '19 at 21:10
  • @Louis-JacobLebel Please tag you question with the correct shell. It is current tagged with [tag:bash]. The echo in [tag:zsh] is likely to have its own quirks. Also, please make it clear in the question how your command actually produces its output. Yes, this matters a lot. If these things are left in comments or can't be determined by reading the actual question, the question will be closed as "unclear". – Kusalananda Oct 06 '19 at 21:15
  • 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. – ljleb Oct 06 '19 at 21:25
  • @Freddy echo $0 returns zsh, so I must be under zsh shell – ljleb Oct 06 '19 at 21:28
2

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:

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
ljleb
  • 113
  • 2
    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 08 '19 at 06:12
-1

Answer

As you know, the > is a output redirector operatory (Essentially meaning it redirectrs the output of a command to a certain place)

If you want to redirect multiple outputs to the same file, then you should use the >> command. It uses the same syntax as the > command but instead of entirely re-writing / erasing the data your previously redirected, it will just add it below.

Example / Syntax

So instead of doing ./my-cmd > file.txt, do ./my-cmd >> file.txt

Can1ne
  • 1
  • all that's true, but has nothing to do with double backslashes getting changed to single backslashes. – ilkkachu Aug 12 '21 at 20:50