Why is the wild card character * so different between commands zip and rm?
You've explained the situation very well. The final piece to the puzzle is that unzip
can handle wildcards itself:
http://www.info-zip.org/mans/unzip.html
file[.zip]
...
Wildcard expressions are similar to those supported in commonly used Unix shells (sh, ksh, csh) and may contain:
* matches a sequence of 0 or more characters
By quoting the * wildcard, you prevented your shell from expanding it, so that unzip
sees the wildcard and deals with expanding it according to its own logic.
rm
, by contrast, does not support wildcards on its own, so attempting to quote a wildcard will instruct rm
to look for a literal asterisk in the filename instead.
The reason that unzip *.zip
does not work is that unzip
's syntax simply does not allow for multiple zip files; if there are multiple parameters, it expects the 2nd and subsequent ones to be files in the archive:
unzip [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^]] file[.zip] [file(s) ...] [-x xfile(s) ...] [-d exdir]
The difference between those two commands is the quoted *
character. If you call a command in a shell and use the *
character for an argument, the shell itself will evaluate the argument. See this example:
$ ls
file1.zip file2.zip file3.zip file4.txt
Now with a *
:
$ ls *.zip
file1.zip file2.zip file3.zip
The shell evaluates the wildcard and builds a command as follows:
$ ls file1.zip file2.zip file3.zip
With a quoted wildcard, it is interpreted as a file named (literally) *.zip
:
$ ls "*".zip
ls: cannot access *.zip: No such file or directory
The unzip
utility cannot be called with multiple zipped files as arguments. But, the developer chose another way for this. From the manpage:
file[.zip]
[...] Wildcard expressions are similar to those supported in commonly used Unix shells (sh, ksh, csh) [...] (Be sure to quote any character that might otherwise be interpreted or modified by the operating system, particularly under Unix and VMS.)
The difference is in the first case the shell itself expands the glob:
% cd /
% echo *
Applications Library Network System Users Volumes bin cores ...
%
while in the second case the application itself Does Something™ with that literal character:
% cd /
% perl -E 'chdir "/tmp" or die; say for glob($ARGV[0])' "*"
com.apple.launchd.aj4FEhYqm5
...
If unquoted, the shell first expands out the glob, and the command will be run with whatever that shell glob expanded out to.