我有一个包含 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
您将获得带有前导零的存档,并且存档中的文件也将按正确的顺序排列。
如果文件名中有空格或换行符,此版本不会中断。