Suppose we have a directory with three files in it: file_1
, file_2
, and the very inconveniently named file 3
. If my understanding of filename expansion is correct, the way bash
interprets the string
echo *
is that it sees the (unquoted) *
, and modifies the string so that it now reads
echo file_1 file_2 file 3
Then, since there are no more expansions to be performed, bash attempts to evaluate the string. In this case, it runs the command echo
, passing to it four arguments: file
, 3
, file_1
, and file_2
. In any case, the outputs are identical:
$ echo *
> file 3 file_1 file_2
$ echo file 3 file_1 file_2
> file 3 file_1 file_2
However, in other contexts, this doesn't seem to be what happens. For instance
$ arr1=( * )
$ arr2=( file 3 file_1 file_2 )
$ echo ${#arr1}
> 3
$ echo ${#arr2}
> 4
And yet, if shell expansion works the way it's described in the bash
documentation, these ought to be identical.
Something similar happens in a for
loop:
$ for f in *; do echo $f; done
> file 3
> file_1
> file_2
$ for f in file 3 file_1 file_2; do echo $f; done
> file
> 3
> file_1
> file_2
What am I missing? Does globbing not happen in these cases?
I'm putting together a GitHub repo to centralize my dotfiles, following this suggestion from MIT's Hacker Tools. The script I'm writing has two usages:
./install.sh DOTFILE [DOTFILE [DOTFILE ...]]
./install.sh -a
In the first case, each of the named dotfiles in src/config
is symlinked to a corresponding dotfile in my home directory; in the second, the -a
flag prompts the script to run as if I had entered every dotfile as an argument.
The solution I came up with was to run ln -sih
in a for
loop using one of two arrays: $@
and *
.1 So, simply assign FILES=( $@ )
or FILES=( * )
, and then run for f in $FILES
--except, it seems to me, *
should break in this assignment if there's a filename with a space in it. Clearly bash
is smarter than me, since it doesn't, but I don't understand why.
if [[ "$f" != "$0" ]]
clause.
From the bash
documentation you linked to:
The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and filename expansion.
Filename expansion happens after word splitting, and therefore the expanded filenames are not themselves subject to further word splitting.