2

Consider a double-quoted command substitution with backslash escapes inside it, like this:

echo "$(echo '\\')"

It prints out \\, whereas I would have expected it to print out only one backslash. My thinking (which is incorrect) was that it went through the whole string, replacing all backslash escapes, and then it would do the command substitution. Evidently, the order is opposite.

However, if we do

echo "$(echo '\')$"

it prints out \$. I would've expected that if it's doing the command substitutions first and then evaluating that string's backslash escapes, that the \ and the $ might combine to make a single $ in the end. But it doesn't.

Where do backslash escapes fit into the order of things?

(The context for this question is that I'm working on something that will properly escape regex characters in a string for insertion into a sed command.)

3 Answers3

2

I think it's best understood by the output of echo $(echo '\\') (i.e. a variant without the outer quotes), which results in \\. The point is that there's no literal string interpretation of the backslash(es) when the command substitution entity $(...) is expanded. (This is similar in case you have escape characters stored in strings; there won't be a re-interpretation as a literal string.)

Janis
  • 14,222
  • The problem with that is that echo $(echo '\\') doesn't necessarily expand to \\\ - or to anything all. – mikeserv Mar 27 '15 at 03:57
2

In a command substitution delimited with $(…), what's inside the parentheses is parsed in the same way as a toplevel command (except in a few corner cases involving unbalanced closing parentheses). What's inside the parentheses is an ordinary shell snippet, there's no additional backslash expansion being done.

The command echo '\\' prints three characters: two backslashes and a newline (assuming an echo command that doesn't do backslash expansion). Therefore the result of a command substitution $(echo '\\') is the two-character string \\ (the final newline is stripped, command substitution always does this). Since you used the command substitution inside double quote, no other expansion is performed: the resulting word part is \\.

In echo "$(echo '\')$", the command substitution outputs a single backslash. Its contribution to the argument to echo is the string \. The following $ is followed by a character that cannot start a parameter name, so it expands to itself. Thus the argument to echo is the two-character string \$. Double-quoted strings are not expanded any further, there is nothing that could cause the backslash to be interpreted as a special character (except some flavors of the echo command).

You can look up the full expansion rules in shell manuals and other documentation, with various degrees of (un)readability. The POSIX specification isn't too bad as standards go (faint praise).

P.S. How to ensure that string interpolated into `sed` substitution escapes all metachars

1

It has more to do with quoting,

$ echo '\'
\
$ echo '\\'
\\
$ echo "\\"
\

With single quotes, whatever is there between quotes is echoed. With double quotes, the shell looks inside and does processing.

kjohri
  • 129