• Uncategorized

About bash : Single-quotes-inside-a-double-quoted-string-in-bash-not-honored

Question Detail

I am trying to assign a variable in bash:

assignssid="airport -I | awk '/ SSID/ {print substr($0, index($0, $2))}'"

When I currently do this, and then run echo "$assignssid", the result is something like the following:

airport -I | awk '/ SSID/ {print substr(-bash, index(-bash, ))}'

How do I get the variable to work with the code inside the quotes?

Question Answer

The Problem: Single Quotes Aren’t Syntactic Within Double Quotes

When you have "'$0'", only those outer quotes are syntactic (and control how the shell expands the value: The inner quotes are simply literal values, and don’t change how $0 is treated.


Literal Answer (bash-only): $”

If you don’t want expansions to be honored, don’t use double quotes.

# assign the directory separately, just to make the line shorter for easier reading
dir=/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/

# now, expand the directory name in double quotes, but use the $'' quoting style otherwise
assignssid="$dir"$'airport -I | awk \'/ SSID/ {print substr($0, index($0, $2))}\''

Inside $'', \' is a literal single quote (likewise, \n is a newline, \t is a tab, etc), and no parameter expansions take place ($'$0' is the same as '$0', not "$0").

After doing this, you can see that echoing the variable emits your command with single-quoted contents intact:

$ echo "$assignssid"
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | awk '/ SSID/ {print substr($0, index($0, $2))}'

…or, more germane to your presumably-intended use case:

current_ssid=$(eval "$assignssid")

Literal Answer (POSIX sh): '"'"'

Let’s do the first answer in a way that isn’t bash-only:

dir=/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/
assignssid="$dir"'airport -I | awk '"'"'/ SSID/ {print substr($0, index($0, $2))}'"'"''

What this string does is as follows:

  • The first ' closes the single-quoted context
  • The first " opens a double-quoted context
  • The following ' is literal, thus becomes part of your value
  • The following " closes the double-quoted context
  • The final ' resumes the original single-quoted context

Best-Practice Answer: Use Functions To Store Code

A string variable isn’t the appropriate tool for this job at all. Instead, use a function:

airport_dir=/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/
assignssid() {
    "$airport_dir"/airport -I | awk '/ SSID/ {print substr($0, index($0, $2))}'
}

…and thereafter:

current_ssid=$(assignssid)

You could “divide and conquer”.
Lets put the (very) long directory in one variable:

$ dir="/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources"

Lets put the awk command in a second variable:

$ awkcmd='/ SSID/ {print substr($0, index($0, $2))}'

As the text is inside single quotes, the $0 and $2 are not expanded by the shell.

And, lets join all in the variable you want:

$ assignssid="$dir/airport -I | awk '$awkcmd'"

The single quotes work (appear in the assignssid variable) in this case because they are being used inside the double quotes.

And, I’ll assume that what you want to execute is:

$ eval "$assignssid"

The above will work in any (reasonable) shell.

Thanks all for your contributions. I think I found a different way to do it
var=$(/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | awk ‘/ SSID/ {print substr($0, index($0, $2))}’)

You may also like...

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.