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

时间:2016-07-13 19:18:25

标签: bash macos gzip tar

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

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

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

4 个答案:

答案 0 :(得分:5)

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

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

如果您只希望cd应用于tar命令,则可以按如下方式执行此操作,将其放在子shell中并使用exec将子shell替换为自身tar命令,避免子shell以其他方式创建的fork惩罚:

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

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

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

注意事项:

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

答案 1 :(得分:2)

尝试:

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

注意:这已在CentOS / RedHat 6.7上成功测试。

答案 2 :(得分:1)

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

$ getconf ARG_MAX

我的回归

131072

或者,您可以为tar创建一个文件列表,并使用-T--files-from F选项获取名称,而不是使用符合max args限制的globbing。

答案 3 :(得分:0)

如下:

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

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

检查Ubuntu手头没有Mac。