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?
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?
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?