为什么 zip 和 rm 命令中的通配符 * 如此不同?

为什么 zip 和 rm 命令中的通配符 * 如此不同?

我编写了一个脚本来为我执行一些文件操作。我使用通配符运算符*将函数应用于某种类型的所有文件,但有一点我不明白。我可以将unzip所有文件放在这样的文件夹中

unzip "*".zip

但是,要随后删除所有 zip 文件,我需要这样做

rm *.zip

也就是说,它不需要引号。另一方面,如果我只给它 *(给我一个警告“文件不匹配”),解压缩将不起作用。

为什么会有所不同?对我来说,这似乎是完全相同的操作。或者我错误地使用了通配符?

外卡介绍在 Unix 中,不要真正深入探讨这一点,而且我无法在rmzip文档中找到任何内容。

我正在 Mac (Yosemite) 上使用终端。

答案1

你已经很好地解释了情况。难题的最后一部分是它unzip本身可以处理通配符:

http://www.info-zip.org/mans/unzip.html

论点

文件[.zip]

...

通配符表达式类似于常用的 Unix shell(sh、ksh、csh)中支持的通配符表达式,并且可能包含:

* 匹配0个或多个字符的序列

通过引用 * 通配符,您可以阻止 shell 扩展它,以便 shellunzip看到通配符并根据其自己的逻辑处理扩展它。

rm相比之下,不支持通配符在其自己的,因此尝试引用通配符将指示rm在文件名中查找文字星号。

unzip *.zip不起作用的原因是unzip的语法根本不允许多个 zip 文件;如果有多个参数,则期望第二个及后续参数是存档中的文件:

解压缩 [-Z] [-cflptTuvz[abjnoqsCDKLMUVWX$/:^]] 文件[.zip] [文件...] [-x x文件...] [-d exdir]

答案2

这两个命令之间的区别在于引号*字符。如果您在 shell 中调用命令并使用该*字符作为参数,则 shell 本身将计算该参数。看这个例子:

$ ls
file1.zip  file2.zip  file3.zip  file4.txt

现在有*

$ ls *.zip
file1.zip  file2.zip  file3.zip

shell 评估通配符并构建命令,如下所示:

$ ls file1.zip  file2.zip  file3.zip

使用带引号的通配符,它​​被解释为名为(字面意思)的文件*.zip

$ ls "*".zip
ls: cannot access *.zip: No such file or directory

unzip无法使用多个压缩文件作为参数来调用该实用程序。但是,开发者为此选择了另一种方式。从联机帮助页:

文件[.zip]

[...] 通配符表达式与常用 Unix shell(sh、ksh、csh)中支持的通配符表达式类似 [...] (请务必引用操作系统可能解释或修改的任何字符,特别是在 Unix 和 VMS 下。)

答案3

区别在于第一种情况是 shell 本身扩展了 glob:

% cd /                                                       
% echo *
Applications Library Network System Users Volumes bin cores ...
% 

而在第二种情况下,应用程序本身会使用该文字字符执行 Something™:

% cd /
% perl -E 'chdir "/tmp" or die; say for glob($ARGV[0])' "*"
com.apple.launchd.aj4FEhYqm5
...

如果不加引号,shell 首先会展开 glob,并且该命令将使用 shell glob 展开到的任何内容来运行。

答案4

由于 zip 处理多个参数的方式,需要引号:

rm:删除参数列表中的所有文件

zip:解压第一个参数中的文件。仅提取剩余参数中的文件。

$ 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

如您所见,它尝试在 file1.zip 中查找 file2.zip 和 file3.zip

为了允许您一次提取多个 zip 文件,zip 支持自行解释 glob,并产生不同的结果。

相关内容