为什么这不能解压给定目录中的所有 zip 文件?
find -name "*.zip" -exec unzip {} + \;
相反,对于每个匹配项,我都会收到“警告:文件名不匹配:”
答案1
分析
find -name "*.zip" -exec unzip {} + \;
此命令本身在 级别上无效find
,它甚至无法运行。命令内的unzip
有效操作由或*终止,而不是同时由两者终止。您的描述仅与由 终止的操作的行为相匹配,因此我认为这是您真正使用的命令:-exec
find
+
\;
+
find -name "*.zip" -exec unzip {} + # still wrong
为什么这不能解压给定目录中的所有 zip 文件?
因为unzip
只需要一个 zip 文件。其他操作数被解释为“要处理的存档成员”(请参阅man 1 unzip
),即您想要从存档中提取的文件。通过使用,-exec unzip {} +
您unzip
可以调用来自扩展的多个参数{}
。除第一个之外的所有参数都被解释为要处理的存档成员,但您不希望它们被这样处理。
* 严格来说:;
中的反斜杠\;
只是为了转义;
在壳里,因此 shell 不会将其;
视为命令终止符。shell 会删除反斜杠,并按应有的方式find
进行处理。;
解决方案
改用-exec unzip {} \;
。此形式将替换{}
为一个路径名。它将产生unzip
比预期更多的进程-exec unzip {} +
,但每个进程unzip
只会处理一个 zip 文件,而这正是该工具所期望的。
find . -type f -name "*.zip" -exec unzip {} \;
我明确指定了.
起始路径以使答案可移植。您的显然默认find
使用,但某些实现需要命令行中至少有一个路径。是以防某个目录(或套接字等)匹配;一般来说可能。.
find
-type f
-name "*.zip"
例子
假设有./foo.zip
和./bar.zip
是唯一匹配的文件。find -name "*.zip" -exec unzip {} +
将执行:
unzip ./foo.zip ./bar.zip
(或unzip ./bar.zip ./foo.zip
)。此命令将尝试./bar.zip
从 中提取./foo.zip
(或反过来)。这不是您想要做的。
另一方面find -name "*.zip" -exec unzip {} \;
将执行:
unzip ./foo.zip
unzip ./bar.zip
或以相反的顺序执行同一对命令。这就是您想要做的。
笔记
上述例子中的顺序没有指定。在实践中这个答案基本正确:
find
将按照项目在目录条目中的存储顺序遍历目录树。[…]
理论上find
是不需要按此顺序遍历,恰好这是一个方便实现的顺序。
无论如何,如果从一个 zip 中提取的文件与存储在另一个 zip 中的文件发生冲突,那么在某个时候unzip
会询问你该怎么做。注意问题涉及哪个档案;不要假设任何特定的档案顺序。
答案2
除了卡米尔的出色回答之外,这里还有一个更隐蔽的问题:使用双引号而不是单引号*.zip
将允许在执行 find 命令期间发生扩展。
请考虑以下示例:
.
目录中有 abc.zip- 有一个或多个子目录包含诸如def.zip,ghi.zip等文件。
当 find 命令执行时,shell 会扩展*.zip
以abc.zip
有效地使您的命令执行为find -name abc.zip -exec . . .
- 这可能不是您想要的。