为什么并非所有文件都压缩以及如何改进解决方案

为什么并非所有文件都压缩以及如何改进解决方案

我有一个文件夹,里面有大约 20K 个文件。这些文件按照模式命名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 上使用 zsh 5.0.2,GNU tar 1.27.1

编辑:

@Archemar 建议的分叉听起来很合理,最新的分叉会覆盖生成的文件 - 该文件包含文件的“尾部” -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尽管我没有意识到这个问题并且对我来说似乎是不连贯的。-atar: You must specify one of the '-Acdtrux', '--delete' or '--test-label' optionsazfAcdtrux

编辑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 看不到文件名?

答案1

您已达到 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 tarunbuntu,-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

答案2

没有必要xargs。如果你直接给出tar选项-T -,它将读取文件名来自标准输入。

例如:

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

答案3

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

  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. 返回前 10 000 个文件

    ${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]}

相关内容