複数のサブディレクトリを圧縮し、各zipファイルにN個のサブディレクトリを含める方法[閉じる]

複数のサブディレクトリを圧縮し、各zipファイルにN個のサブディレクトリを含める方法[閉じる]

私は読んだこれ。しかし、私は少し違うことを達成しようとしています。

多くのサブディレクトリがあるディレクトリがあります。これらのサブディレクトリを使用してzipファイルを作成したいのですが、各サブディレクトリごとに別々のzipファイルを作成するのではなく、グループ化したいと思います。各zipファイルに10個のサブディレクトリがあるとします。

編集:すべてのサブディレクトリは1レベルです!

とても感謝しています。

答え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
...

以下は、位置パラメータを繰り返すがサブシェルを生成しないいくつかの異なるバージョンです。 (このバージョンは以前のバージョンよりも速く動作します)

#!/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 私たちが多数のディレクトリを扱う場合、最初の2つのバージョンでいくつかの深刻な問題が発生する可能性があると思いました。メモリに重大な負担をかけることに加えて、最初の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個未満のサブディレクトリを含めることができます。

質問に引用された回答では、サブディレクトリごとに1つのfor i in */; do zip -r "${i%/}.zip" "$i"; doneZIPファイルではなく、10個のサブディレクトリを1つの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
...

関連情報