Search code examples
bashshellquotesquotingparameter-expansion

Reason for inconsistent behavior of single quotes during BASH parameter expansion?


When using BASH Parameter Expansion, string that variable expands into can be quoted/escaped, which works fine, except when the single quotes are used and the whole variable is escaped in double quotes:

$ echo "${var:-\\a}"
\a # ok
$ echo "${var:-"\\a"}"
\a # ok
$ echo "${var:-$'\\a'}"
\a # ok
$ echo "${var:-'\a'}"
'\a' # wtf?

Interestingly, $' ' quotes work normally, while ' ' don't. Single quotes start working correctly if the variable itself is not quoted:

$ echo ${var:-'\a'}
\a

But, that can lead to other issues if $var itself contains whitespace characters.

Is there any good reason for this inconsistency?


Solution

  • I think this is the most relevant quote from the source code (y.tab.c):

      /* Based on which dolstate is currently in (param, op, or word),
         decide what the op is.  We're really only concerned if it's % or
         #, so we can turn on a flag that says whether or not we should
         treat single quotes as special when inside a double-quoted
         ${...}. This logic must agree with subst.c:extract_dollar_brace_string
         since they share the same defines. */
      /* FLAG POSIX INTERP 221 */
    
      [...]
    
      /* The big hammer.  Single quotes aren't special in double quotes.  The
         problem is that Posix used to say the single quotes are semi-special:
         within a double-quoted ${...} construct "an even number of
         unescaped double-quotes or single-quotes, if any, shall occur." */
      /* This was changed in Austin Group Interp 221 */
    

    It's not exactly clear to me why single quotes aren't special, but it seems like a conscious choice made after long (and I've been told contentious) debate preceding the change. But the fact is (if I am summarizing this correctly), single quotes here are just regular characters, not syntactic quotes, and are treated literally.