我需要创建一个 zip 文件,将包含约 500k 个文件的目录中的约 100k 个文件存档。当我尝试以下显而易见的命令时,我收到“参数列表太长”错误:
zip archive.zip *pattern*.txt # fails
zip archive.zip `find . -name "*pattern*.txt"` # fails
一种方法是使用-@
通过 stdin 传入文件列表的选项:
find . -name "*pattern*.txt" | zip -@ archive.zip
但是,zip
手册页上写道:
如果文件列表指定为 -@ [不在 MacOS 上],则 zip 将从标准输入而不是命令行获取输入文件列表。
让我烦恼的是“不在 MacOS 上”这个选项。我继续尝试这个-@
选项,它似乎有效;但我担心它是否真的能正常工作(完整地存档所有文件)。
以下是我的问题:
- 为什么
-@
在 MacOS 上不行? - 在 MacOS/bash/zip 的某些版本中是否存在此警告,而在其他版本中是否存在此警告?这是一个过时的警告吗?如果是,那么分界线在哪里?
- 如果不使用的话,解决这个问题的可行方法是什么
-@
?
请注意这里给出的解决方案zip:参数列表太长(总共 80,000 个文件)将不起作用;我需要存档目录中的部分文件,而不是全部文件。
我正在运行 Mac OS 10.7.5。以下是一些版本信息:
$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
$ zip --version
This is Zip 3.0 (July 5th 2008), by Info-ZIP.
...
Compiled with gcc 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00) for Unix (Mac OS X) on Jun 24 2011.
答案1
首先,
zip archive.zip `find . -name "*pattern*.txt"`
是绝不好主意。文件名可以包含空格、换行符、可以解释为开关的部分等等。
要对找到的每个文件执行操作,您可以使用-exec
切换或参数。
find . -name "*pattern*.txt" -exec zip archive.zip {} +
会将文件逐个添加到 zip 文件中。此处,{}
表示当前正在处理的文件。
-exec
用 a 来终止参数+
会;
导致 find 同时处理多个文件(尽可能多的文件,而不会产生与您所遇到的相同的错误),这对于大量文件来说应该会快得多。
find . -name "*pattern*.txt" -print0 | xargs -0 zip archive.zip
本质上是一样的。xargs 默认一次处理多个文件。
切换-print0
到 find 并-0
切换到 xargs 使它们使用空字符作为文件分隔符,以正确处理奇怪的文件名。
我不知道为什么-@
不推荐用于 Mac OS 1,find ... | zip -@
但是不是正确处理奇怪的文件名(具体来说,包含换行符的文件名)。无论使用哪种操作系统,这都是正确的。
1我猜测这仅适用于 Mac OS 9.x 及以下版本,因为 Mac OS 使用回车符作为换行符,而zip -@
需要换行符。
答案2
Dennis 是对的,这是 OS 9 的问题。我查看了 Zip 3.0 的源代码。在macos/
平台目录中,有一条注释:
此移植适用于 Mac OS X 之前的 Mac 版本。由于 Mac OS X 是基于 Unix 构建的,因此请使用适用于 Mac OS X 的 Unix 移植。- 2008 年 6 月 7 日
此外,该zip.c
文件将命令行选项的声明包装在 中#ifndef MACOS
。换句话说,如果我运行 的“MacOS”端口zip
,该-@
选项就会失败。
丹尼斯还给出了“一种可行的方法来完成任务-@
”的答案,即,
find . -name "*pattern*.txt" -print0 | xargs -0 zip archive.zip
我同意这是防止出现“奇怪”文件名(带有空格、换行符等的文件名)的最佳方法。但是,这会降低性能。 xargs
将zip
多次调用,每次都将一大组文件名作为命令行参数传递。 zip
将在每次调用时将这些文件添加到其中archive.zip
。但每次调用时zip
都需要读取越来越大的文件archive.zip
,随着作业的进展,这会花费越来越多的时间。
如果你知道一定所讨论的文件名不包含空格或换行符等病态字符,然后单次通过
find . -name "*pattern*.txt" | zip -@ archive.zip
会更快;而且它在 OS X 上工作得很好,因为zip
OS X 实际上是 Unix 端口。手册页中的警告不适用。
答案3
正如您的版本信息所示,基础代码(因此文档可能也是如此)相当老旧,在此期间 MacOS 已经发生了很大变化。此外,构建版本比基础代码新得多,构建版本的代码/配置可能会发生更改,只是从未写入文档中。
无论如何,最好检查(也许用一个小例子)该命令是否有效,并且是否真正存储了它被要求存储的文件。如果这很重要,不要相信随机互联网网站上缺少部分的彩色方块……