如何压缩大量子目录,并让每个zip文件包含N个子目录

如何压缩大量子目录,并让每个zip文件包含N个子目录

我读了。但我正在努力实现一些略有不同的目标。

我有一个包含许多子目录的目录。我想使用这些子目录创建 zip 文件,但我不想为每个子目录创建单独的 zip 文件,而是将它们分组——假设每个 zip 文件有 10 个子目录。

编辑:所有子目录都是一层的!

非常感谢。

答案1

因此,我假设您想要分组的所有子目录都位于父目录下的某一深度级别。我们将zip递归到子目录中。

编辑:感谢人们的建议,这个新版本现在可以处理所有类型的文件名,包括包含空格、换行符和特殊字符的名称。关于此事的精彩文章可以在这里找到: https://unix.stackexchange.com/a/321757/439686

#!/bin/bash
export rootdir=${1:-/your/parent/directory}
export N=10 # group size
export stamp=$(date +%s)

find "$rootdir" -type d -mindepth 1 -maxdepth 1  -exec bash -c '
   count=0 # group number
   while [ $# -gt 0 ] ;do
     ((count++))
     zip -r "$rootdir/group.${stamp}.${count}.zip" "${@:1:N}"
     shift $N || set --
   done
' "" {} +

结果:

group.1615512971.1.zip
group.1615512971.2.zip
group.1615512971.3.zip
group.1615512971.4.zip
...

这是一个略有不同的版本,它也循环遍历位置参数,但不会生成子 shell。 (这个版本比之前的版本执行得更快)

#!/bin/bash
rootdir=/your/parent/directory
N=10 # group size
stamp=$(date +%s)

readarray -td '' ARRAY < <(find "$rootdir" -type d -mindepth 1 -maxdepth 1 -print0)
set -- "${ARRAY[@]}"

count=0
while [ $# -gt 0 ] ;do
  ((count++))
  zip -r "$rootdir/group.${stamp}.${count}.zip" "${@:1:N}"
  shift $N || set --
done

编辑#2:并行性和内存使用

读完这篇文章后: https://unix.stackexchange.com/a/321765/439686 我突然想到,如果我们处理大量目录,我的前两个版本可能会遇到一些严重的问题。除了对内存造成严重压力之外,它们的效率也很低,因为find在我们启动第一个命令之前它们就在等待找到整个目录列表zip。如果我们通过管道并行运行事情会好得多,然后有多少文件就不再重要了。这给我们留下了唯一可能的正确解决方案——用 来做find ... -print0 | xargs -0 command。为什么xargs?因为它可以一次使用 N 个参数启动命令,而不是等待整个列表,而且还因为可以处理将通过管道传递给它的xargs零分隔字符串。-print0我们绝对必须使用零作为分隔符,因为文件名允许有任何其他字符,包括换行符。作为额外的好处,xargs我们甚至可以同时启动多个进程,以更好地利用多核系统。所以,这里是:

#!/bin/bash
rootdir=${1:-/your/parent/directory}
N=10 # group size
mktemp --version >/dev/null || exit 1
stamp=$(date +%Y%m%d%H%M)
cores=$(nproc) || cores=1
export rootdir N stamp cores

find "$rootdir" -type d -mindepth 1 -maxdepth 1 -print0 \
  | xargs -r0  --max-args=$N  --max-procs=$cores  bash -c '
  zip -r "$(mktemp -u -p "$rootdir" group.$stamp.XXXXXX.zip)" "$@" ' ""

结果:

group.202103140805.7H1Don.zip
group.202103140805.akqmgX.zip
group.202103140805.fzBsUZ.zip
group.202103140805.iTfmj8.zip
...

答案2

您可以zip -r zipfile files_or_dirs多次调用相同的内容zipfile并循环执行此操作。

下面的脚本将递归地将当前目录的 10 个子目录(其中包含所有文件和子目录)添加到 ZIP 文件,然后切换到下一个 ZIP 文件。它将忽略当前目录中的文件。 ZIP 文件的大小取决于子目录中的数据。最后一个 ZIP 文件可能包含少于 10 个子目录。

由于该问题引用的答案使用for i in */; do zip -r "${i%/}.zip" "$i"; done并声明了唯一的附加要求,例如应将 10 个子目录存储在一个 ZIP 文件中,而不是每个子目录一个 ZIP 文件,因此我认为不需要存档以点开头的目录。

#!/bin/bash
zipnum=0
i=0
for dir in ./*/
do
    zip -r archive$zipnum.zip "$dir" # recursively add this dir to the archive
    ((i++))            # count directories
    if [[ i -ge 10 ]]  # maximum number of directories per ZIP file
    then
        i=0            # reset directory counter
        ((zipnum++))   # next ZIP file number
    fi
done

请注意,如果您稍后更改子目录集,则 ZIP 文件的目录分配可能会发生变化,因此重复执行脚本时可能会得到不同(或意外)的结果。

由于脚本计数 0、1、...、9、10、11...,您可能会得到具有不同位数的 ZIP 文件,这可能会导致意外的(字典顺序)排序,例如

archive0.zip
archive1.zip
archive10.zip
archive11.zip
archive2.zip
archive3.zip
...

相关内容