迭代压缩文件

迭代压缩文件

我有一个包含 77K PDF 的文件夹(大小约为 500 GB)。我想将它们压缩成 77 个压缩文件,每个文件包含 1000 个 PDF,以便更容易上传并与同行共享。我不知道如何在 bash 中编写 for 循环并在那里使用 zip 命令,但我看到了一些示例问题。有人可以帮我吗?

文件名如下:

FinalRoll_MR_ACNo_@PartNo_%%.pdf

@ 和 %% 是数字。如果我可以将前 1000 个文件压缩到像 archive_1.tar.gz 这样的文件中,那就太好了!如果我们能保留文件的顺序按字母顺序排列,那就更好了!

我正在使用运行 Ubuntu 的 AWS ec2 实例。

提前致谢!

答案1

#!/usr/bin/perl

use strict;
use List::MoreUtils qw(natatime);
use Sort::Naturally;

# specify directory on command line, or default to .
my $dir = shift || '.';

# Find all the PDF files. 
#
# NOTE: you could use perl's `Find::File` module instead of
# readdir() to do a recursive search like `find`.
opendir(DIR, $dir) || die "Can't open $dir: $!\n";
my @pdfs = nsort grep { /\.pdf$/i && -f "$dir/$_" } readdir(DIR);
closedir(DIR);

my $size=1000;

my $i=1;
my $iter = natatime $size, @pdfs;
while( my @tmp = $iter->() ){
  my $tarfile="archive_" . sprintf('%02i',$i++) . ".tar.gz";
  #print join(" ", ('tar','cfz',$tarfile, @tmp)),"\n";
  system('echo','tar','cfz',$tarfile, @tmp);
}

这使用natatime()PerlList::MoreUtils库模块中的 (“n-at-a-time”) 函数一次迭代 1000 个 PDF 文件列表。

它还使用该Sort::Naturally模块对 PDF 文件名进行自然排序。如果您不需要或不想要的话,请删除它(以及线路nsort上的呼叫)。my @pdfs = ...

tar 文件名中包含 2 位零填充数字,以便正确排序。如果您有足够的 PDF 文件来填充超过 99 个 tar 存档,请将其更改为 3 位或更多位数。

所写的代码是试运行'echo',从函数调用中删除system(),使其真正打包 PDF 文件批次。

要在不使用 的情况下运行时获得详细输出echo,请取消注释该print语句。顺便说一句,很容易让它打印时间戳,例如自纪元以来的秒数,使用 perl 内置time(),或者使用模块很好地格式化Date::Format。例如:

print join(" ", (time(),'tar','cfz',$tarfile, @tmp)),"\n";

另存为,例如,vibhu.pl使其可执行chmod +x vibhu.pl。这是一个示例运行(在只有 10 个“.pdf”文件的目录中):

$ touch {1..10}.pdf
$ ./vibhu.pl 
tar cfz archive_01.tar.gz 1.pdf 2.pdf 3.pdf 4.pdf 5.pdf 6.pdf 7.pdf 8.pdf 9.pdf 10.pdf

如果您更改$size=1000为,例如$size=3,您可以看到它实际上一次执行 N 个 pdf 文件:

$ ./vibhu.pl 
tar cfz archive_01.tar.gz 1.pdf 2.pdf 3.pdf
tar cfz archive_02.tar.gz 4.pdf 5.pdf 6.pdf
tar cfz archive_03.tar.gz 7.pdf 8.pdf 9.pdf
tar cfz archive_04.tar.gz 10.pdf

列表::更多实用工具排序::自然模块可从CPAN。它们可能已经打包供您分发。例如在 Debian 上:

sudo apt-get install liblist-moreutils-perl libsort-naturally-perl

答案2

使用 bash shell,您可以将文件名放入数组中(使用通配符扩展自然排序),然后在索引循环中一次切出 1000 个:

#!/bin/bash

filenames=( *.pdf )
for((index=1; index <= $(( (${#filenames[@]} / 1000) + 1)); index++))
do
  start=$(( (index-1) * 1000 ))
  tar czf archive"${index}".tar "${filenames[@]:start:999}"
done

for循环根据需要运行多次,以便每次运行获取 1000 个文件。该start变量指示数组切片应从何处开始。该tar命令为数组中的 1000 个文件创建一个索引 tar 文件,从 999 个文件开始到start接下来的 999 个文件(或最后剩下的所有文件)。

答案3

您可以使用此 awk 脚本来创建 shell 脚本。查看 compress.sh 然后执行它:

ls *.pdf | awk 'BEGIN {ORS=""; print "#!/bin/sh"; } NR%1000 == 1 {  print "\nzip Archive_" NR ".zip"; } { print " \\\n" $0; }' > compress.sh

答案4

使用 find 和 xargs 的替代方案,因为您不应该解析ls

export numfile="$(mktemp)"
echo 0 > "$numfile"

find lots_of_files/ -name '*.pdf' -print0 \
| sort -V -z \
| xargs -0r -L 1000  \
bash -c 'NUM=$(cat "$numfile") ; ((NUM++)); echo "$NUM" > "$numfile"; \
  tar -czf archive_$(printf '%03d' "$NUM" ).tar.gz "$@"' tar_in_batches

rm "$numfile"
unset numfile

您将获得带有前导零的存档,并且存档中的文件也将按正确的顺序排列。

如果文件名中有空格或换行符,此版本不会中断。

相关内容