0

In bash

$ va='\\abc'
$ echo $va
\\abc

In the assignment va='\\abc', the single quotes preserve the two backslashes in the value of va.

In the echo command echo $va, Is it correct that bash first performs parameter expansion on $va (expand it to \\abc), and then performs quote removal on the result of parameter expansion? Quote removal removes backslash and quotes, but why are the two backslashes still preserved? I expect the result to be \abc. For comparison

$ echo \\abc
\abc

Do I miss something in the bash manual? I appreciate that someone can point out what I miss.

Thanks.

  • 1
    I think you are forgetting that using ' takes out the meaning of what follows ahead. – Rui F Ribeiro Nov 14 '18 at 1:01
  • I am asking about echo $va, where there is no single quote stored in $va or involved in any way. – Tim Nov 14 '18 at 1:02
  • 1
    @Tim Quote and escape parsing, removal, etc all happen before variable references are expanded. The only port-processing done on (non-quoted) variable expansions is word splitting and wildcard expansion. – Gordon Davisson Nov 14 '18 at 5:00
5

Start with a simpler comparison:

$ echo '\\abc'
\\abc
$ echo \\abc
\abc

In the first command, the apostrophes do not become part of the argument to echo because they have been used for quoting. All of the characters inside, including both backslashes, are passed to echo.

In the second command, the first backslash quotes the second backslash. The one that was used for quoting does not become part of the argument to echo. The other one is passed to echo, along with the abc (which was not quoted, but that doesn't matter because they are not metacharacters).

Now we're ready to talk about your command sequence

$ va='\\abc'
$ echo $va
\\abc

When the assignment command is executed, the apostrophes quote everything between them. The apostrophes do not become part of the value assigned, but everything else does, including both backslashes.

In the echo command, there are no quoting characters. The value of va is retrieved and inserted into the argument list. Now there is an argument containing 2 backslashes, but they don't function as quoting characters, because the parsing phases where we were looking for quoting characters was done before variable expansion.

Variable expansion is not like macro expansion. The resulting series of arguments is not fed back in to the full command line parser. Some post-processing is done (word-splitting and globbing) but there is not a second pass of quote removal and variable expansion.

When you want to build an argument list and reparse the whole thing as a new command line with all shell features available, you can use eval. This is usually a bad idea because "all shell features" is a lot, and if you aren't careful, something bad can happen.

$ va='\\abc'
$ eval echo $va
\abc

Perfect, right?

$ va='\\abc;rm -rf $important_database'
$ eval echo $va
\abc
^C^C^C ARGH!

When you find yourself wanting to use shell quoting syntax inside the value of a shell variable, try to think of a different way to solve your problem.

3

Do I miss something in the bash manual?

Yes. From the manual:

After the preceding expansions, all unquoted occurrences of the characters ‘\’, ‘'’, and ‘"’ that did not result from one of the above expansions are removed.

The "preceding expansions" and "above expansions" here being parameter (variable) expansion, command substitution, etc.

-2

The answer is simple, the line:

echo $va

does not contain quotes that need to be removed.

This is how the shell has been defined since more than 40 years already. Note that the Bourne Shell first appeared AT&T internally in 1976.

BTW: "quoting" in this regard meant characters with the 8th bit on in the 1970s. So this in a shell internal form of quoting.

Since the Bourne Shell has been reworked to support 8-bit characters, in the mid 1980s, this internal form of quotuing has been replaced by backslashes in the internal strings before any quoted character.

Today, the Bourne Shell works the following way:

  • Strings that are written in single quotes are replaced by the backslash form. This e.g. means that 'abc' is replaced by \a\b\c

  • Strings with explicitely typed backslashes are kept internally.

  • Strings with double quotes keep their double quotes, so "abc" remains internally "abc"

When doing parameter expansion, the shell replaces all kind of quoted strings (see three forms above) by the form with single backslashes before any char and this is what is removed while doing "quote removal".

BTW: the variable expansion:

abc=123

done with

command "$abc"

results in

command \1\2\3

before quote removal is done.

command $abc

results in

command 123

before quote removal is done.

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.