Bash parsing and shell expansion

匿名 (未验证) 提交于 2019-12-03 01:22:02

问题:

I'm confused in the way bash parses input and performs expansion.

For input say, \'"\"hello world\"" passed as argument in bash to a script that displays what its input is, I'm not exactly sure how Bash parses it.

Example,

var=\'"\"hello   world\"" ./displaywhatiget.sh "$var" I got '"hello   world" 

I understand that the double quotes in "$var" tells bash to treat the value of var together. However, what I don't understand is when is the backslash escaping and double-quoted parsing for the value takes place in bash's expansion process.

I'm coming from shell-operation, and shell expansion.

回答1:

All of the interesting things happen in the assignment, var=\'"\"hello world\"". Let's break it down:

  • \' - this is an escaped single-quote. Without the escape, it would start a single-quoted string, but escaped it's just a literal single-quote. Thus, the final string will start with '.
  • " - this starts a double-quoted string.
  • \" - an escaped double-quote; like the escaped single-quote, this gets treated as a literal double-quote, so " will be the second character of the final string.
  • hello world - since we're still in a double-quoted string, this just gets included literally in the final string. Note that if we weren't in double-quotes at this point, the space would've marked the end of the string.
  • \" - another escaped double-quote; again, included literally so the last character of the final string will be ".
  • " - this closes the double-quoted string.

Thus, var gets assigned the value '"hello world". In ./displaywhatiget.sh "$var", the double-quotes mean that $var gets replaced by var's value, but no further interpretation is done; that's just passed directly to the script.

UPDATE: When using set -vx, bash prints the assignment in a somewhat strange way. As I said in a comment, what it does is take the original command, parse it (as I described above) to figure out what it means, then back-translate that to get an equivalent command (i.e. one that'd have the same effect). The equivalent command it comes up with is var=''\''"hello world"'. Here's how that would be parsed:

  • '' - this is a zero-length single-quoted string; it has no effect whatsoever. I'm not sure why bash includes it. I'm tempted to call it a bug, but it's not actually wrong, just completely pointless. BTW, if you want an example of quote removal, here it is: in this command, these quotes would just be removed with no trace left.
  • \' - this is an escaped single-quote, just like in the original command. The final string will start with '.
  • ' - this starts a single-quoted string. No interpretation at all is performed inside single-quotes, except for looking for the close-quote.
  • "hello world" - since we're in a single-quoted string, this just gets included literally in the final string, including the double-quotes and space.
  • ' - this closes the single-quoted string.

so it gets the same value assigned to var, just written differently. Any of these would also have the same effect:

var=\''"hello world"' var="'\"hello world\"" var=\'\"hello\ world\" var="'"'"hello world"' var=$'\'"hello world"' 

...and many others. bash could technically have printed any of these under set -vx.



回答2:

The parsing of the \-prefixed escape sequences happens on assignment:

var=\'"\"hello   world\"" 

causes Bash to store the following literal in $var: '"hello world".

On later referencing $var inside a double-quoted string ("$var") the above literal becomes a literal part of that double-quoted string - no interpretation of the value of $var is performed at this point.

What double-quoted strings expand to is treated as a single word (argument) by the shell (after removing the enclosing double quotes, a process called quote removal).



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!