为什么不是所有文件都被压缩以及如何改善解决方案


8

我有一个约有2万个文件的文件夹。文件根据模式命名xy_{\d1,5}_{\d4}\.abc,例如xy_12345_1234.abc。我想使用以下命令压缩其中的前10K:

ls | sort -n -k1.4,1.9 | head -n10000 | xargs tar -czf xy_0_10000.tar.gz

但是,生成的文件中只有大约2K个文件。

ls | sort -n -k1.4,1.9 | head -n10000 | wc -l 但是返回10000,如预期的那样。

在我看来,我对这里的一些基本知识误解了。

我在Linux Mint 17.1和GNU tar 1.27.1上使用zsh 5.0.2

编辑:

@Archemar建议的分支听起来很合理,最新的fork覆盖了结果文件-该文件包含文件的“尾部” -77739999

的结果xargs --show-limit Your environment variables take up 3973 bytes POSIX upper limit on argument length (this system): 2091131 POSIX smallest allowable upper limit on argument length (all systems): 4096 Maximum length of command we could actually use: 2087158 Size of command buffer we are actually using: 131072

在我的情况下替换-c-r-u不起作用。错误消息是tar: Cannot update compressed archives

同时使用-r-u是无效的,并且失败tar: You may not specify more than one '-Acdtrux', '--delete' or '--test-label' option

替换-c-a似乎也是无效的,并且以相同的方式失败,tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' options尽管我不认识这个问题azf,但对我而言Acdtrux似乎是分离的。

编辑2:

-T看起来是个好方法,我也在这里找到了一个例子。

但是当我尝试

ls | sort -n -k1.4,1.9 | head -n10000 | tar -czf xy_0_10000.tar.gz -T - 我得到 tar: option requires an argument -- 'T'

好吧,也许文件名没有达到tar?但是看起来像他们,是因为当我执行时

ls | sort -n -k1.4,1.9 | head -n10000 | tar --null -czf xy_0_10000.tar.gz -T - 我得到 tar: xy_0_.ab\nxy_1_...<the rest of filenames separated by literal \n>...998.ab Cannot stat: File name too long

那么,为什么tar无法看到文件名呢?


如果您尝试使用a而不是c,请在tar命令中使用?
Olivier Dulac

5

1
OP的文件没有棘手的名称。
Archemar

@ 8bittree-关于健壮的shell脚本的一般建议,是的。但是,对于使用一次性一次性常规文件列表处理文件,您有什么建议呢?
kostja

1
@kostja我将使用find,它可以-print0选择使用空字节作为定界符而不是换行符。sort可以用-z标志来处理。head,不幸的是不能处理理解的空字节定界符,但是这个答案有一个使用trswap \n\0before and after 的解决方案headtar必须--null -T -从中读取以空分隔的文件名stdin
8bittree

Answers:


12

您达到了xargs的限制?

xargs --show-limit

尝试:

  • 创建一个虚拟.tgz文件tar czf xy_0_10000.tar.gz /hello/world
  • 替换-czf-Azf

当xarg达到其极限时,它将分叉命令,因此您最终运行的命令是

  tar czf xy_0_10000.tar.gz file1 file2 .... file666
  tar czf xy_0_10000.tar.gz file667 file668 ... file1203
  tar czf xy_0_10000.tar.gz file1024 ... file2000

当每个tar覆盖上一个tar时,您只会得到最后一个tar c运行。

编辑:

1)根据man taron unbuntu,-a并且-r似乎等效的附加操作是由(任一)完成的 -A, --catenate, --concatenate

2)zip(不是gzip)可以用来添加文件,也许gzip选项可以解决问题。(使用 | xargs zip -qr xy_0_0000.zip,这将生成一个zip文件,而不是.tar.gz)

3)使用@rsanchez的解决方案
以正确的方式向tar添加选项很重要,请尝试

ls | sort -n -k1.4,1.9 | head -n10000 |tar -czf xy_0_10000.tar.gz -T -

其中- -T -表示使用选项-T-用作参数-T(您可能已经在中生成文件列表/tmp/foo.lst,然后使用-T /tmp/foo.lst


是否可以(= add)代替c(= create / overwrite)解决该限制?
Olivier Dulac

@OlivierDulac(警告:这是一个纯粹的猜测)由于tar无法创建空文件,因此它可能无法解决。您可以先压缩一个空文件夹,然后将a (add)其添加到tar文件中。然后,您可以打开tar并删除文件夹(使用7zip等)
Ismael Miguel

@ismaelmiguel:我很确定它将愉快地创建文件。如果不是,则只是:touch xy_0_10000.tar.gz && { _the full command here_ ; }
Olivier Dulac

1
@OlivierDulac这将是一个无效的.gz文件。
Ismael Miguel

我从manpages.ubuntu.com/manpages/vivid/zh-CN/man1/tar.1.html(15.04)回到精确(12.04)看到的所有手册页都有-r附加文件,但-a自动压缩是不等效的。并且-rz不起作用:zip可以添加到现有存档中,因为该目录未压缩,但是tar通过压缩将元数据与数据一起压缩。您可以将其tar -r分段成一个未压缩的存档,然后将其gzip 压缩。还是...
dave_thompson_085

12

不需要xargs。如果直接给出tar-T -选项,它将从标准输入中读取文件名

例如:

... | tar -T - -czf xy_0_10000.tar.gz

我似乎错误地使用了该选项,无法使其与管道一起使用。已经试过...| tar Tczf xy_......| tar Tcz -f xy_... ...| tar -czf xy_... -T 等几个排列,但只有我得到tar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' optionstar: -f: Cannot stat: No such file or directory如果使用-f单独从其他选项和tar: option requires an argument -- 'T'。您能否添加一个用法示例?
kostja

添加了@kostja示例。
rsanchez 2015年

非常感谢,rsanchez。不知道为什么选项列表-T -末尾带有的变体tar不起作用,但是您的示例起作用了。不幸的是,我的问题实际上有两个部分-错误的来源和可能的改进。当您授予后者时,Archemar擅长于前者,而几乎拥有后者的权利。我不确定您接受哪个答案,因为它们显然都对您有所帮助。
kostja

1

我想用zsh解决方案来补充其他两个答案,该解决方案既不解析ls也不需要xargs。但是,我现在不确定,它是否也受到命令行长度的限制。

  1. 定义一个函数,通过修改生成所需的排序键$REPLY

    sortkey() { REPLY=${REPLY[4,9]} }

    这相当于你的 sort -n -k1.4,1.9

  2. 生成一个数组$files,文件名使用上述函数排序:

    files=(*(o+sortkey))

    这相当于 ls | sort -n -k1.4,1.9

  3. 返回前10000个文件

    ${files[0,9999]}

    这相当于 ls | sort -n -k1.4,1.9 | head -n10000

因此,所有这些都应该可以解决问题:

sortkey() { REPLY=${REPLY[4,9]} }
files=(*(o+sortkey))
tar -czf xy_0_10000.tar.gz ${files[0,9999]}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.