从 1,000,000 个 .json 文件(不包括任何目录)创建一个 .tar.gz 文件的终端命令

Terminal command to create a .tar.gz files from 1,000,000 .json files (without including any directory)

我有一个包含 1,000,000 个 .json 文件的目录,并使用以下命令仅从 json 文件(不包括 /Library/WebServer/a/a/e/j/ 路径)构建 j.tar.gz :

cd /Library/WebServer/a/a/e/j && tar -zcvf j.tar.gz *.json

发生此错误:...Argument list too long。你会建议一个更好的命令来完成这个任务吗?谢谢。

您的系统设置了限制。您可以查看

$ getconf ARG_MAX

我的returns

131072

或者,您可以为 tar 创建一个文件列表并使用 -T--files-from F 选项来获取名称而不是 globbing,这会达到最大参数限制。

尝试:

find . -type f -name "*.json" > ./include_file && tar -zcvf j.tar.gz --files-from ./include_file

注意:这已在 CentOS/RedHat 6.7.

上成功测试

最初的警告:tar 不是标准定义的工具(POSIX 存档器是 pax),因此它的行为可能因平台而异,没有任何最低保证基线。您的里程可能会有所不同。


因为这是为 bash 标记的,您可以使用 <() -- 进程替换 -- 生成一个文件名,当读取时,将发出子进程的输出而不需要临时文件。 (如果您的操作系统支持它们,这通常会实现为 /dev/fd 名称,否则会实现为命名管道)。

如果您只想将 cd 应用于 tar 命令,您可以按如下方式进行,将其放入子 shell 并使用 exec让 subshell 用 tar 命令替换自己,避免 subshell 否则造成的 fork 惩罚:

dir=/Library/WebServer/a/a/e/j
(cd "$dir" && exec tar --null -zcvf j.tar.gz -T <(printf '%s[=10=]' *.json) )

或者,如果您的 tar 支持它,您可以使用 --include 告诉 tar 自己过滤名称:

tar -C "$dir" --include='*.json' -cvzf "$dir/j.tar.gz" .

注意事项:

  • printf '%s\n' *.json 不受此影响,因为 printf 是一个 shell 内置;因此,glob 结果不会放入 execv-family 系统调用的参数中,因此 ARG_MAX 不适用。
  • find 上使用 --null,在 printf 上使用 '%s[=30=]'(如果您使用 find 生成姓名列表,则使用 -print0 ) 可以防止恶意生成的带有文字换行符的名称能够将任意名称注入到您的流中。想想如果有人运行 mkdir -p $'hello/\n/etc/passwd\n.json' 会发生什么——你不希望 /etc/passwd 进入你的 tarball。

怎么样:

> cd /Library/WebServer/a/a/e/j
> find . -name '*.json' -maxdepth 1 | xargs tar -czvf j.tar.gz --add-file

它不需要临时文件,也不需要在 shell 中执行 *.json 这会失败。

在 Ubuntu 上查看过 Mac 手头没有。