Why does this Bash pathname expansion not take place?

658 Views Asked by At

I'm struggling with Bash variable expansion. Please see the following code:

~/tmp 689$ a=~/Library/Application\ *; echo $a
/Users/foo/Library/Application *

~/tmp 690$ echo ~/Library/Application\ *
/Users/foo/Library/Application Scripts /Users/foo/Library/Application Support

As the order of expansion is brace->tilde->parameter->....->pathname, why is pathname expansion not applied to $a in the same way that it is in the 2nd command?

[added]

Does whitespace escaping have hidden behaviour regarding the following output?

~/tmp 705$ a=~/Library/Application*; echo $a
/Users/foo/Library/Application Scripts /Users/foo/Library/Application Support
1

There are 1 best solutions below

1
On BEST ANSWER

To do what you meant to do, you'd have to use the following:

a=(~/Library/Application\ *)  # use an *array* to capture the pathname-expanded results
echo "${a[@]}"                # output all array elements (without further expansion)

As for why your code didn't work:

In the context of variable assignment involving only literals or string interpolation (references to other variables), NO pathname expansion takes place, even with unquoted strings (e.g., a=*, a="*", and a='*' all assign literal *)[1].

(By contrast, pathname expansion is applied to unquoted strings inside an array definition (e.g., a=(*), or inside a command substitution (e..g, a=$(echo *)).)

Thus, the literal content of $a is /Users/foo/Library/Application *

Executing echo $a - i.e., NOT double-quoting the variable reference $a - then applies word splitting and does the following:

  • it prints literal '/Users/foo/Library/Application' (the 1st word - no expansion applied, due to its contents)
  • it prints the pathname expansion applied to * (the 2nd word - i.e., it expands to matching filenames in the current dir.)

The fact that the latter results in * in your case implies that you happen to be running the echo command from an empty directory (save for hidden files, assuming the default configuration).


[1]Whether the string is unquoted or not does, however, matter with respect to tilde expansion; e.g., a=~ expands ~ to the user's home directory, whereas a='~' or a="~" assign literal ~.