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

ARGUMENTS

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.