
나는 각각 텍스트 줄을 포함하는 수천 개의 작은 텍스트 파일(1-5MB) 덤프를 가지고 있습니다. 각 배치가 고정된 크기(예: 100MB)가 되도록 "일괄 처리"하고 해당 배치를 압축해야 합니다.
이제 해당 배치는 다음과 같습니다.
- 개별 텍스트 파일 내용의 '고양이'인 단일 파일, 또는
- 개별 텍스트 파일 자체만
주의사항:
split -b
텍스트 줄을 그대로 유지해야 하므로 여기서는 유닉스가 작동하지 않습니다.lines
각 줄의 바이트 수에 큰 차이가 있기 때문에 옵션을 사용하는 것은 약간 복잡합니다.- 파일 크기가 요청된 크기의 5% 이내라면 엄격하게 고정된 크기일 필요는 없습니다.
- 라인은 중요하며 손실되어서는 안 됩니다. 입력이 손실 없이 출력으로 전달되었는지 확인해야 합니다. 롤링 체크섬(CRC32와 같지만 충돌 시 더 좋고/"더 강력"함)
스크립트는 훌륭하게 작동해야 하지만 이것은 누군가가 이전에 수행한 작업인 것처럼 보이며 적어도 유사한 작업을 수행하는 일부 코드(가급적 Python 또는 Ruby)를 보는 것이 좋을 것입니다.
답변1
다음 스크립트는 지정된 디렉터리 내에 압축된 파일 패키지를 생성합니다. 다음과 같이 호출합니다.
script.sh directorypath
(설명한 것과 마찬가지로) 간단하고 순진한 알고리즘을 사용합니다.
- 모든 파일을 계산합니다.
- 모든 파일을 재귀적으로 읽기 시작합니다.
- 각 파일의 크기, ls 항목 및 체크섬(SHA1)을 가져옵니다. (ls 항목을 매니페스트.txt에 저장하고 체크섬을 checksum.txt에 저장합니다.)
- 크기가 제한을 초과한 경우, 매니페스트.txt 목록을 사용하여 압축된 tar(매니페스트 및 체크섬 파일도 포함)를 만듭니다.
- 임시 디렉토리를 생성하고 방금 생성한 tar의 압축을 해제합니다.
- 방금 추출한 파일의 새 체크섬을 계산합니다.
- 저장된 체크섬과 비교합니다.
- 하나 이상의 체크섬이 다른 경우 오류와 함께 종료됩니다.
- 그렇지 않으면 삭제 옵션이 활성화되어 있는지 확인하고, 그렇다면 소스 파일을 제거하십시오.
- 더 이상 파일이 없을 때까지 반복합니다.
출력은 다음과 같습니다:
Reading files...
15898 849 ../out/f068715p.jpg
Creating package (pack18.tar.gz) with 849 files, using 100078420 bytes...
tar: Removing leading `../' from member names
Preparing to verify package...
Creating new checksums...
Comparing checksums...
Package verification OK.
Deleting temporary verification directory...
Reading files...
16731 833 ../out/f069111c.jpg
Creating package (pack19.tar.gz) with 833 files, using 100004735 bytes...
tar: Removing leading `../' from member names
Preparing to verify package...
Creating new checksums...
Comparing checksums...
Package verification OK.
Deleting temporary verification directory...
Reading files...
패키지 파일은 현재 디렉터리에 생성됩니다.
한 가지 경고:
- 현재 디렉터리와 소스 디렉터리는 부모/자식 또는 자식/부모가 아니어야 하며 그런 방식으로 테스트되지 않았습니다.
다음은 스크립트입니다(PACKSIZELIMIT는 바이트 수입니다. DELETESOURCE가 1이면 소스 파일이 삭제됩니다. [음, "rm -f" 행 앞에 있는 # 기호도 제거해야 합니다]):
#!/bin/bash
PACKSIZELIMIT=100000000
PACKPREFFIX="pack"
#PACKSUFFIX=$(date +"_%Y%m%d_%H%M")
PACKSUFFIX=""
DELETESOURCE=0
LISTFILE="packbatchlist.txt"
MANIFESTFILE="manifest.txt"
CHECKSUMFILE="checksums.txt"
VERIFYFILE="verifysums.txt"
if [ -d "$1" ]; then
PACKCOUNTER=0
PACKSIZE=0
FILECOUNTER=0
ALLFILECOUNTER=0
cat /dev/null > $LISTFILE
cat /dev/null > $MANIFESTFILE
cat /dev/null > $CHECKSUMFILE
cat /dev/null > $VERIFYFILE
echo "Reading files..."
TOTALFILES=$(find "$1" -type f | wc -l)
echo "There are $TOTALFILES files to process..."
find "$1" -type f | while read SOURCEFILE ; do
let "FILECOUNTER+=1"
let "ALLFILECOUNTER+=1"
echo -ne "\r$ALLFILECOUNTER $FILECOUNTER $SOURCEFILE\e[K"
THISFILESIZE=$(stat -c %s "$SOURCEFILE")
let "PACKSIZE+=$THISFILESIZE"
echo $SOURCEFILE >> $LISTFILE
ls -l $SOURCEFILE >> $MANIFESTFILE
sha1sum $SOURCEFILE >> $CHECKSUMFILE
if [ $PACKSIZE -gt $PACKSIZELIMIT -o $ALLFILECOUNTER -eq $TOTALFILES ]; then
echo
echo $MANIFESTFILE >> $LISTFILE
echo $CHECKSUMFILE >> $LISTFILE
PACKFILENAME="$PACKPREFFIX$PACKCOUNTER$PACKSUFFIX.tar.gz"
echo "Creating package ($PACKFILENAME) with $FILECOUNTER files, using $PACKSIZE bytes..."
tar -cf - -T $LISTFILE | gzip -c > $PACKFILENAME
echo "Preparing to verify package..."
TEMPCHECKDIR=$(mktemp -d)
tar xzf $PACKFILENAME -C $TEMPCHECKDIR
if [ -r "$TEMPCHECKDIR/$CHECKSUMFILE" ] ; then
cut -d " " -f 1 $TEMPCHECKDIR/$CHECKSUMFILE > $VERIFYFILE
sort $VERIFYFILE > $TEMPCHECKDIR/$CHECKSUMFILE
echo "Creating new checksums..."
cat /dev/null > $VERIFYFILE
find "$TEMPCHECKDIR" -type f | while read CHECKEDFILE ; do
CHECKEDFILESHORT=$(basename $CHECKEDFILE)
if [ "$CHECKEDFILESHORT" != "$MANIFESTFILE" -a "$CHECKEDFILESHORT" != "$CHECKSUMFILE" ] ; then
sha1sum $CHECKEDFILE | cut -d " " -f 1 >> $VERIFYFILE
fi
done
sort $VERIFYFILE -o $VERIFYFILE
echo "Comparing checksums..."
DIFFFILES=$(comm --nocheck-order -3 $TEMPCHECKDIR/$CHECKSUMFILE $VERIFYFILE | wc -l)
if [ $DIFFFILES -gt 0 ] ; then
echo "ERROR: Package failed verification!"
exit 2
else
echo "Package verification OK."
echo "Deleting temporary verification directory..."
find "$TEMPCHECKDIR" -delete
if [ "$DELETESOURCE" == "1" ] ; then
echo "Deleting source files..."
cat $LISTFILE | while read FILE2DEL ; do
echo -ne "\rDeleting $FILE2DEL ... \e[K"
#rm -f $FILE2DEL
done
echo -e "\rFiles deleted.\e[K"
fi
fi
else
echo "ERROR: Cannot find checksum file from package!"
exit 1
fi
let "PACKCOUNTER+=1"
PACKSIZE=0
FILECOUNTER=0
cat /dev/null > $LISTFILE
cat /dev/null > $MANIFESTFILE
cat /dev/null > $CHECKSUMFILE
cat /dev/null > $VERIFYFILE
echo "Reading files..."
fi
done
else
echo
echo "Missing source directory"
echo
fi
rm -f $LISTFILE
rm -f $MANIFESTFILE
rm -f $CHECKSUMFILE
rm -f $VERIFYFILE
답변2
GNU 분할에는 -C
유사 -b
하지만 줄을 나누지 않는 옵션이 있습니다.