Why is the wild card character * so different between the zip and rm commands?

I put together a script to do some file operations for me. I am using the wild card operator * to apply functions to all files of a type, but there is one thing I don’t get. I can unzip all files in a folder like this

unzip "*".zip

However, to remove all zip files afterward, I need to do

rm *.zip

That is, it does not want the quotation marks. The unzip, on the other hand, does not work if I just give it the * (gives me a warning that “files were not matched”).

Why is this different? To me, this seems like the exact same operation. Or am I using the wild card incorrectly?

Introductions to the wild card in Unix do not really go into this, and I could not locate anything in the rm or zip docs.

I am using the terminal on a Mac (Yosemite).

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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]

Method 2

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.)

Method 3

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.

Method 4

A command will receive the arguments after they have been processed by the shell.

On first processing, an unquoted * will be expanded by the shell (to the list of files in the present directory (pwd) that match the pattern):

echo *.zip

Will list all .zip files. But echo "*".zip" will not.

On first processing, a quoted "*" will not be expanded, it will be given to the command unzip as a parameter (after quoting has been removed). The command unzip will receive a parameter of *.zip:

$ echo unzip "*".zip
unzip *.zip

It is the command unzip which expand the * to the list of files.


It is also interesting that this two commands will not perform the exact same final action, and who expands the * changes:

unzip "*".zip                ### the command unzip expands `*.zip`.
unzip *.zip                  ### the shell expands `*.zip`.

The first command receives a *.zip which it expands to process all files.
The second command unzip will receive a list of all .zip files in the pwd, which it will not process, as the unzip developer has chosen to reject the expansion of more than one zip file.

Method 5

The quotes are needed because of the way zip handles multiple arguments:

rm: remove all files in the argument list

zip: unzip the file in the first argument. only extract the files in the remaining arguments.

$ ls *.zip
file1.zip  file2.zip  file3.zip
$ unzip *.zip
Archive:  file1.zip
caution: filename not matched:  file2.zip
caution: filename not matched:  file3.zip

as you can see, it tries to find file2.zip and file3.zip inside file1.zip

in order to allow you to extract multiple zip files at once, zip supports interpreting the glob by itself, with a different result.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x