Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash parsing and shell expansion

Tags:

linux

bash

shell

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.

like image 430
htcm8 Avatar asked Mar 11 '23 03:03

htcm8


1 Answers

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.

like image 145
Gordon Davisson Avatar answered Mar 20 '23 10:03

Gordon Davisson