我读了这。但我正在努力实现一些略有不同的目标。
我有一个包含许多子目录的目录。我想使用这些子目录创建 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
...