Nested double quotes in parameter expansion

Viewed 94

I was surprised that the following is a valid Parameter Expansion. Notice there are unescaped double quotes within double quotes:

result="${var1#"$var2"}"

Can someone please parse this for me?

2 Answers

There are double quotes nested in curly brackets which is OK.

But none of them is needed in this case.

result=${var1#$var2}

works the same even for values containing spaces and newlines.

The answer is that they get parsed separately. Let's take a simplified tour of the string.

result="${var1#"$var2"}" doesn't actually need any quotes in this case, but look over the string anyway...

result="...

The Parser says meh, it's an assignment, I know what to do with this, I'll ignore these, they aren't hurting anything, but now I have to find the terminating match. Then it reads the value after the quote, byte by byte, looking for the terminating double-quote. This starts a new context-1.

result="${...

Once it sees the open curly, it knows that the terminating quote cannot happen until it sees the matching closing curly. It starts a new context-2.

result="${var1#"...

Seeing a new double quote in this subcontext make this one the opening quote of an internal new context-3.

result="${var1#"$var2"...

When it sees this double-quote it matches it to the previous one, closing context-3, dropping back into context-2.

result="${var1#"$var2"}...

This close-curly allows it to close the still-open context-2, dropping back into context-1.

result="${var1#"$var2"}"

And finding this now-closing double-quote allows it to close context-1. The following newline may be used as a terminating character for the entire term, so it can be evaluated and assigned.

Backslash-Quoting the internal double-quotes, for example, would have added them to the string-term used for the tail trim, which would likely have failed because of it.

$: var1=aaa
$: var2=a
$: result="${var1#"$var2"}"
$: echo $result                # does what you want/expect
aa
$: result="${var1#\"$var2\"}"  # does NOT
$: echo $result
aaa

Doing it without the quotes, the parser knows this is an assignment and handles the values a little differently as mentioned in comments, but generally kinda treating them as if they were quoted.

$: result=${var1#$var2}
$: echo $result
aa

This means it doesn't have to deal with context-1 or context-3, and only has the curlies to worry about. The end result is the same.

Better?

Related