为什么这不能解压给定目录中的所有文件?

为什么这不能解压给定目录中的所有文件?

为什么这不能解压给定目录中的所有 zip 文件?

find -name "*.zip" -exec unzip {} + \;

相反,对于每个匹配项,我都会收到“警告:文件名不匹配:”

答案1

分析

find -name "*.zip" -exec unzip {} + \;

此命令本身在 级别上无效find,它甚至无法运行。命令内的unzip有效操作由或*终止,而不是同时由两者终止。您的描述仅与由 终止的操作的行为相匹配,因此我认为这是您真正使用的命令:-execfind+\;+

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 会扩展*.zipabc.zip有效地使您的命令执行为find -name abc.zip -exec . . .- 这可能不是您想要的。

相关内容