Why do the following two codes work as expected:
ls -d .[!.]?*
echo [D]*
But the following 2 don't:
ls -d [.][!.]?*
echo [D]
In the first command, I get an error:
ls: cannot access [.][!.]*: No such file or directory
When I am trying to get the same listing ls -d .[!.]?*
. And for the second, the output is:
[D]
When I'm expecting an error proclamation along the lines of No such file or directory
. What am I missing? What exactly makes an expression a wildcard, if those wildcard elements shown in the second set of examples above don't cut it?
Clarification (Also in comments):
The wildcard [D]*
doesn't only output D
, it also outputs Desktop
, Downloads
… etc. However, I also tried echo [D]
when I had a file named D and when I didn't. The output worked when the file D
was there, but I also got the output [D]
when it wasn't. I don't get why. Why did the presence of the file in the directory change the expression [D] from being a wild card to not?
Best Answer
By default, bash (the shell) doesn't expand a filename beginning with a dot (considered a hidden file) unless the dot is explicitly specified. Since
[.]
is a pattern, rather than a literal character, it doesn't trigger the display of hidden files and sols -d [.][!.]?*
doesn't match anything.You can change this default behavior by running
shopt -s dotglob
, which sets the option to always includes hidden files when expanding filename patterns (known as "globbing").Example (the dollar sign at the beginning of the line indicates the shell prompt; don't type it in):
The issue with
echo [D]
is that expansion doesn't happen if no filename is matched. Since you didn't have a file namedD
when you tried it,echo
was given, and echoed, what you literally entered.An example of pathname expansion only occurring when a filename matches:
If you delete all of the files which match
[D]*
, thenecho [D]*
will give you[D]*
.