다수의 하위 디렉터리를 압축하고 각 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
...

다음은 위치 매개변수를 반복하지만 하위 쉘을 생성하지 않는 약간 다른 버전입니다. (이 버전은 이전 버전보다 더 빠르게 작동합니다)

#!/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파이프로 연결될 0으로 구분된 문자열을 처리할 수 있기 때문입니다. -print0줄 바꿈을 포함하여 파일 이름에 다른 문자가 허용되므로 반드시 0을 구분 기호로 사용해야 합니다. 추가 보너스로 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하위 디렉터리당 하나의 ZIP 파일이 아닌 10개의 하위 디렉터리를 하나의 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
...

관련 정보