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

pat*_*ick 62 shell zip wildcards rm

我整理了一个脚本来为我做一些文件操作。我正在使用通配符运算符*将函数应用于一种类型的所有文件,但有一件事情我不明白。我可以unzip像这样的文件夹中的所有文件

unzip "*".zip
Run Code Online (Sandbox Code Playgroud)

但是,之后要删除所有 zip 文件,我需要执行

rm *.zip
Run Code Online (Sandbox Code Playgroud)

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

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

Unix 中通配符的介绍并没有真正涉及到这一点,我在rmzip文档中找不到任何内容。

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

Jef*_*ler 75

你已经很好地说明了情况。拼图的最后一部分是unzip可以处理通配符本身:

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

论据

文件[.zip]

...

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

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

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

rm相比之下,不支持通配符自身,因此试图引用一个通配符将指示rm来寻找文件名,而不是字面星号。

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

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

  • @patrick 使用一次只能处理一个文件的程序处理多个文件的 unix 方法是使用循环。例如`for f in *.zip ; 解压 -v "$f" ; 完成`。以及为什么 shell 进行文件名扩展等的很大一部分原因是每个单独的程序都不必这样做(这将导致有许多独立编写的通配符扩展实现,这些实现在小而烦人的方面有所不同) . (12认同)
  • pkzip 起源于 DOS,它没有扩展传递给程序的通配符。 (7认同)
  • 谢谢,有道理!如果我理解正确,在一种情况下我说的是 `unzip` 自己的语言,在另一种情况下是通用的 unix 行话? (6认同)
  • 正确的。重要的是要记住你的 shell 做什么与程序做什么。 (6认同)

cha*_*aos 25

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

$ ls
file1.zip  file2.zip  file3.zip  file4.txt
Run Code Online (Sandbox Code Playgroud)

现在有一个*

$ ls *.zip
file1.zip  file2.zip  file3.zip
Run Code Online (Sandbox Code Playgroud)

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

$ ls file1.zip  file2.zip  file3.zip
Run Code Online (Sandbox Code Playgroud)

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

$ ls "*".zip
ls: cannot access *.zip: No such file or directory
Run Code Online (Sandbox Code Playgroud)

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

文件[.zip]

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


thr*_*rig 8

不同之处在于在第一种情况下,shell 本身扩展了 glob:

% cd /                                                       
% echo *
Applications Library Network System Users Volumes bin cores ...
% 
Run Code Online (Sandbox Code Playgroud)

而在第二种情况下,应用程序本身使用该文字字符做某事™:

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

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