크기가 비슷한 여러 유사한 파일을 여러 개의 아카이브로 tar.gz하는 방법


11

우분투 16.04에 있습니다.

많은 텍스트 파일 (약 12k)이있는 폴더가 있습니다. 업로드를 허용 .tar.gz한 다음 자동으로 압축 해제 하는 웹 사이트에 파일을 모두 업로드해야 하지만 파일 당 10MB (10000KB)로 제한됩니다 (특히 각 파일의 압축을 해제해야 함). 나는 경우 tar.gz모든 파일 결과 파일은 72메가바이트 약이다.

내가하고 싶은 것은 .tar.gz각각 크기 / 크기 (엄격하게) 10000KB보다 작은 8 개의 파일 을 만드는 것입니다.

또는 위의 모든 파일의 크기가 거의 동일하다고 가정 할 수 있으므로 .tar.gz각각 동일한 파일 양이 많거나 적은 8 개의 파일 을 만들고 싶습니다 .

이 두 가지 작업을 어떻게 수행 할 수 있습니까?

GUI, CLI 또는 스크립팅이 포함 된 솔루션으로 완벽하게 작동합니다. 나는 여기서 속도를 찾지 않고 단지 완료해야합니다.


아마도 12k 파일은 이름에 패턴이나 반복되는 문자가있을 것입니다. tar파일을 모두 가질 때까지 특정 패턴으로 시작하는 모든 파일을 추가하여 파일을 추가 할 수 있습니다. 이 스크립트는 쉽게 스크립팅 할 수 있지만 필요에 따라 크기가 9MB보다 작다는 보장은 없습니다. 그러나 너무 큰 파일을 더 분할하여 크기를 수동으로 조정할 수 있습니다.
Juan Antonio

답변:


9

완전히 패치 워크와 빠르고 대략적인 스케치이지만 3000 개의 파일이있는 디렉토리에서 테스트 한 결과 아래 스크립트는 매우 빠른 작업을 수행했습니다.

#!/usr/bin/env python3
import subprocess
import os
import sys

splitinto = 2

dr = sys.argv[1]
os.chdir(dr)

files = os.listdir(dr)
n_files = len(files)
size = n_files // splitinto

def compress(tar, files):
    command = ["tar", "-zcvf", "tarfile" + str(tar) + ".tar.gz", "-T", "-", "--null"]
    proc = subprocess.Popen(command, stdin=subprocess.PIPE)
    with proc:
        proc.stdin.write(b'\0'.join(map(str.encode, files)))
        proc.stdin.write(b'\0')
    if proc.returncode:
        sys.exit(proc.returncode)

sub = []; tar = 1
for f in files:
    sub.append(f)
    if len(sub) == size:
        compress(tar, sub)
        sub = []; tar += 1

if sub:
    # taking care of left
    compress(tar, sub)

사용하는 방법

  • 빈 파일에 다음과 같이 저장하십시오 compress_split.py
  • 헤드 섹션에서 압축 할 파일 수를 설정하십시오. 실제로, 남은 몇 가지 "왼쪽 오버"를 처리하는 것이 항상 하나 더 있습니다.
  • 파일을 인수로하여 디렉토리에서 실행하십시오.

    python3 /path/tocompress_split.py /directory/with/files/tocompress

번호가 매겨진 .tar.gz파일은 파일이있는 디렉토리와 동일한 디렉토리에 작성됩니다.

설명

스크립트 :

  • 디렉토리의 모든 파일을 나열합니다
  • tar 파일에 경로 정보를 추가하지 못하도록 디렉토리에 cd
  • 파일 목록을 읽고 세트 구분으로 그룹화합니다.
  • 하위 그룹을 번호가 매겨진 파일로 압축

편집하다

MB 단위 크기로 청크 자동 생성

청크의 최대 크기 (MB)를 (두 번째) 인수로 사용하는 것이 더 정교합니다. 아래 스크립트에서 청크는 임계 값에 도달 (통과)하자마자 압축 파일에 기록됩니다.

스크립트는 청크에 의해 트리거되므로 임계 값을 초과하므로 (모든) 파일의 크기가 청크 크기보다 실질적으로 작은 경우에만 작동합니다.

스크립트 :

#!/usr/bin/env python3
import subprocess
import os
import sys

dr = sys.argv[1]
chunksize = float(sys.argv[2])
os.chdir(dr)

files = os.listdir(dr)
n_files = len(files)

def compress(tar, files):
    command = ["tar", "-zcvf", "tarfile" + str(tar) + ".tar.gz", "-T", "-", "--null"]
    proc = subprocess.Popen(command, stdin=subprocess.PIPE)
    with proc:
        proc.stdin.write(b'\0'.join(map(str.encode, files)))
        proc.stdin.write(b'\0')
    if proc.returncode:
        sys.exit(proc.returncode)

sub = []; tar = 1; subsize = 0
for f in files:
    sub.append(f)
    subsize = subsize + (os.path.getsize(f)/1000000)
    if subsize >= chunksize:
        compress(tar, sub)
        sub = []; tar += 1; subsize = 0

if sub:
    # taking care of left
    compress(tar, sub)

실행하려면

python3 /path/tocompress_split.py /directory/with/files/tocompress chunksize

... chunksize는 tar 명령 의 입력 크기입니다 .

여기에는 @DavidFoerster가 제안한 개선 사항이 포함되어 있습니다. 감사합니다 많이 !


@ dadexix86 천만에요!
Jacob Vlijm

나는 쉘 호출을 제거하고 인수 목록을 직접 사용했습니다. 여전히 큰 인수 목록은 문제가 될 수 있으며 tar표준 입력 스트림에 파일 목록을 제공하여 호출을 더 개선하려고 노력할 것 입니다.
David Foerster

안녕 @DavidFoerster, 나는 당신의 통찰력을 신뢰하지만 장점은 무엇입니까?
Jacob Vlijm

대부분의 런타임 환경에는 명령의 인수 문자열의 총 길이에 대해 (소프트 및 하드) 제한이있어 수천 개의 파일에서 작업 할 때 빠르게 도달 할 수 있습니다. 그렇기 때문에 tar적절한 옵션으로 표준 입력에 추가하거나 추출 할 파일을 지정할 수 있습니다.
David Foerster

@DavidFoerster 문제가 있지만 두 번째 문제는 더 이상 실행되지 않습니다. 실제로 그들 중 어느 것도 ...
Jacob Vlijm

6

순수한 쉘 접근법 :

files=(*); 
num=$((${#files[@]}/8));
k=1
for ((i=0; i<${#files[@]}; i+=$num)); do 
    tar cvzf files$k.tgz -- "${files[@]:$i:$num}"
    ((k++))
done

설명

  • files=(*): 파일 목록을 저장하십시오 (있는 경우 디렉토리 files=(*.txt), txt확장자 가있는 항목 만 가져 오도록 변경하십시오 ) $files.
  • num=$((${#files[@]}/8));: ${#files[@]}는 배열의 요소 수입니다 $files. 는 $(( ))연산을하는 떠들썩한 파티의 (제한적) 방법입니다. 따라서이 명령 $num은 파일 수를 8로 나눈 값으로 설정 합니다.
  • k=1 : tarball의 이름을 지정하는 카운터 일뿐입니다.
  • for ((i=0; i<${#files[@]}; i+=$num)); do: 배열의 값을 반복합니다. $i0배열의 첫 번째 요소 에서 초기화 되고 씩 증가합니다 $num. 이것은 우리가 모든 요소 (파일)를 겪을 때까지 계속됩니다.
  • tar cvzf files$i.tgz -- ${files[@]:$i:$num}: bash는, 당신은 사용하여 배열 슬라이스 (배열의 일부를) 얻을 수 ${array[@]:start:length}그래서, ${array[@]:2:3}두 번째부터 세 가지 요소를 반환합니다. 여기에서는 현재 값에서 시작하고 요소 길이 $i$num긴 슬라이스를 사용합니다 . 는 --로 시작할 수있는 파일 이름의 경우에 필요하다 -.
  • ((k++)) : 증분 $k

좋은! 처음으로 bash 배열 인덱스 범위를 실제로 사용하는 것을 보았습니다.
Joe

매우 깨끗하고 간결합니다. 나에게는 파이썬 솔루션보다 더 이해할 만하지 만 둘 다 꽤 좋습니다. 모두 성능면에서 어떻게 비교되는지 궁금하십니까?
DocSalvager
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.