우분투 16.04에 있습니다.
많은 텍스트 파일 (약 12k)이있는 폴더가 있습니다. 업로드를 허용 .tar.gz
한 다음 자동으로 압축 해제 하는 웹 사이트에 파일을 모두 업로드해야 하지만 파일 당 10MB (10000KB)로 제한됩니다 (특히 각 파일의 압축을 해제해야 함). 나는 경우 tar.gz
모든 파일 결과 파일은 72메가바이트 약이다.
내가하고 싶은 것은 .tar.gz
각각 크기 / 크기 (엄격하게) 10000KB보다 작은 8 개의 파일 을 만드는 것입니다.
또는 위의 모든 파일의 크기가 거의 동일하다고 가정 할 수 있으므로 .tar.gz
각각 동일한 파일 양이 많거나 적은 8 개의 파일 을 만들고 싶습니다 .
이 두 가지 작업을 어떻게 수행 할 수 있습니까?
GUI, CLI 또는 스크립팅이 포함 된 솔루션으로 완벽하게 작동합니다. 나는 여기서 속도를 찾지 않고 단지 완료해야합니다.
답변
완전히 패치 워크와 빠르고 대략적인 스케치이지만 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가 제안한 개선 사항이 포함되어 있습니다. 감사합니다 많이 !
답변
순수한 쉘 접근법 :
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
: 배열의 값을 반복합니다.$i
는0
배열의 첫 번째 요소 에서 초기화 되고 씩 증가합니다$num
. 이것은 우리가 모든 요소 (파일)를 겪을 때까지 계속됩니다.tar cvzf files$i.tgz -- ${files[@]:$i:$num}
: bash는, 당신은 사용하여 배열 슬라이스 (배열의 일부를) 얻을 수${array[@]:start:length}
그래서,${array[@]:2:3}
두 번째부터 세 가지 요소를 반환합니다. 여기에서는 현재 값에서 시작하고 요소 길이$i
가$num
긴 슬라이스를 사용합니다 . 는--
로 시작할 수있는 파일 이름의 경우에 필요하다-
.((k++))
: 증분$k