Why don't "echo -e" commands seem to produce the right output?

In the terminal of Ubuntu 18.04 LTS, when I write this command:

echo -e "Hello\\\n"

It gives this as the output:

Hello\n

But it should print, as the man page says:

Hello\

That is, first print Hello, then \, then a newline character (and then another newline). Where is the problem?

See these few echo -e commands and their output:

man420@man420-X542UQ:~$ echo -e "HEllo\a\a\a\a\a\a\\\n"
HEllo\n
man420@man420-X542UQ:~$ echo -e "HEllo\\\n"
HEllo\n
man420@man420-X542UQ:~$ echo -e "HEllo\a\\\n"
HEllo\n

Backslashes are treated specially by echo -e, but first they are sometimes treated specially by the shell (which in this case is bash), according to the shell's quoting rules.

The argument echo actually sees is Hello\\n. Because you have passed -e to echo, it treats backslash escapes specially, and \\ is collapsed to a single \. The final n is not escaped, so it appears literally.

The reason for this is that, prior to and separately from the operation of echo itself, the shell treats \ specially in some contexts but not others. Unquoted \ characters are always treated specially, single-quoted \ are never treated specially, but the treatment of double-quoted \ characters, as in the command you ran, is more subtle and complicated.

When the shell encounters double-quoted text in a command, as with "Hello\\\n", it treats \ as an escape character when it precedes a character that can itself have special meaning inside double quotes and not otherwise.

  1. Because \ sometimes has a special meaning inside "", a \ that immediately precedes another \ has the effect of quoting that second \. So inside double quotes, the first \\ are collapsed into \.
  2. After those first two \ characters, there is a third \ character which is unaffected by those first two and which precedes an n. But n is not a character that is ever treated specially inside double quotes, so the \ before it is not treated specially in this situation. Thus \n stays \n.

The effect is that, in double quotes, \\\n is interpreted as \\n.

When echo -e sees \\n, the first \ removes special meaning from the second, so echo prints \n literally for that text.


If your goal is to print Hello with an extra newline but no backslashes (the question was originally ambiguous about this, plus I think it is a useful example), then one solution is to remove a \. Running echo -e "Hello\\n" outputs Hello with an extra newline at the end.

A better solution is to use single quotes and write echo -e 'Hello\n'. Single quotes are the strongest form of quoting. An even better solution is usually to use printf instead of echo, which in this case would be printf 'Hello\n\n'.

If your goal is to print Hello\ including the backslash, followed by an extra newline, then the double-quoted approach is possible but cumbersome. To figure it out, work backwards: echo -e converts \\ to \ and \n to a newline, and double-quoting converts \\ to \, so you can do it with six backslashes (echo -e "Hello\\\\\\n"), because \\n turns into \n due to one backslash escaping another. You can also do it with five, because double-quoting retains \n when the \ is not escaped.

This illustrates the benefit of single quoting: just put whatever you want echo -e to see inside the single quotes (echo -e 'Hello\\\n'). printf is also good here. One option is printf 'Hello\\\n\n'. But where printf really shines is that you can plug in additional arguments. You can use printf '%s\n\n' 'Hello\', which inserts the second argument (literally Hello\ because single quotes don't change anything) in place of %s.