큰 디렉토리 트리를 지정된 크기의 청크로 분할합니까?


11

광 디스크에 백업하려는 디렉토리 트리가 있습니다. 불행히도, 그것은 하나의 디스크 크기를 초과합니다 (약 60GB). 이 트리를 하드 링크 또는 기타가있는 적절한 크기의 덩어리로 나눌 스크립트를 찾고 있습니다 (원본은 그대로 유지). 그런 다음 이러한 바이트 크기의 트리를 백업 프로세스에 공급할 수 있습니다 (PAR2 중복성 추가 등).

멋진 스크립트는 아니지만 이미 완료된 것 같습니다. 제안?

(파일을 굽기 전에 더 많은 작업을 원하기 때문에 한 번에 스패닝 및 쓰기 작업을 수행 할 필요가 없습니다.)


Bluray 작가를 고려한 적이 있습니까?
bsd

2
DVD 미디어는 신뢰할 수 없습니다 ... 외부 드라이브, Carbonite와 같은 온라인 백업 또는 미디어를 굽는 경우 약간의 par2보호 기능을 사용하는 것이 좋습니다 .
Aaron D. Marasco

답변:


7

이를 위해 설계된 응용 프로그램이 있습니다. dirsplit

일반적으로 cdrkit또는 dirsplit패키지에 있습니다.

K3b 또는 기타 GUI 소프트웨어를 사용하여 DVD를 쉽게 만들 수있는 링크가있는 즉시 사용 가능한 폴더를 만들 수 있습니다.


이것은 정말 잘 작동했습니다. 우분투에서는 genisoimage패키지 에서 찾았습니다 .
nograpes


2

한때 비슷한 목적으로 못생긴 대본을 만들었습니다. 그것은 단지 kludge이지만, 작성했을 때 나는 실행 시간이나 예쁘기를 신경 쓰지 않았습니다. 나는 같은 개념의 더 "생산 된"버전이 있다고 확신하지만, 해킹을 시작하기 위해 아이디어 나 무언가를 얻으려면 여기에 간다 (2008 년 했으므로 자신의 위험 부담으로 사용하십시오!) :- )

#!/bin/sh -
REPO=/export/foton/PictureStore
LINKS=/export/foton/links
SPLITTIX=`date '+%y%m%d-%H%M'`

# kilobytes
DVDSIZE=4400000
PARTPREFIX="DVD-"
REPOSIZE=`du -sk -- ${REPO} | awk '{print $1}'`
NUMPARTS=`expr $REPOSIZE / $DVDSIZE`
SPLITDIR=${LINKS}/splits/${SPLITTIX}
mkdir -p -- "$SPLITDIR"

PARTNUM=1
PARTSIZ=0
DONESIZ=0
PARTNUM=`echo $PARTNUM | awk '{printf("%03x", $0)}'`
mkdir -p -- "${SPLITDIR}/${PARTPREFIX}${PARTNUM}"
for D in "${REPO}"/..?* "${REPO}"/.[!.]* "${REPO}"/*
do
  if [ ! -e "$D" ]; then continue; fi  # skip ..?*, .[!.]* and * if there are no matching files
  D=${D#$REPO/}
  D_SIZ=`du -sk -- "${REPO}/$D" | awk '{print $1}'`
  if test `expr $D_SIZ + $PARTSIZ` -le $DVDSIZE
  then
    # link to D in this part
    ln -s -- "$REPO/$D" "${SPLITDIR}/${PARTPREFIX}${PARTNUM}/$D"
    # adjust counters
    PARTSIZ=`expr $PARTSIZ + $D_SIZ`
    DONESIZ=`expr $DONESIZ + $D_SIZ`
  else
    # next part and link to D in that
    echo PART $PARTNUM: $PARTSIZ kb '(target' $DVDSIZE 'kb)'
    PARTNUM=`expr $PARTNUM + 1`
    PARTNUM=`echo $PARTNUM | awk '{printf("%03x", $0)}'`
    PARTSIZ=$D_SIZ
    DONESIZ=`expr $DONESIZ + $D_SIZ`
    mkdir -p -- "${SPLITDIR}/${PARTPREFIX}${PARTNUM}"
    ln -s -- "$REPO/$D" "${SPLITDIR}/${PARTPREFIX}${PARTNUM}/$D"
  fi
done
echo "wrote $DONESIZ kb in $PARTNUM parts in $SPLITDIR"

나는 삼바를 통해 디스크를 구운 창 호스트와 결과를 공유했다고 생각합니다. 위의 변경되지 않은 것을 사용하는 경우 mkisofs심볼릭 링크를 해결하는 다른 아카이버 나 다른 아카이버 를 사용할 수 있습니다 .


파일 이름의 특수 문자 (공백, 초기 대시 및 점 \[?*) 에 대처하기 위해 스크립트를 약간 변경했습니다 . 제안 읽기 : ls , $ VAR vs $ {VAR} 의 출력을 구문 분석하지 않고 인용하거나 인용하지 마십시오 . 결과 스크립트를 테스트하지 않았습니다. 내 변경 사항을 이해하지 못하면 언제든지 문의하십시오.
Gilles 'SO- 악한 중지'

@Gilles : 2008 년 이후로 많은 것을 읽었습니다. ;-)보다 일반적인 스크립트를 만들기위한 변경이 좋습니다. (난의 도입 싫어하는 [반대를 test하지만) ...
MattBianco

이러한 변수의 대부분은 소문자 여야합니다. 일반적으로 환경 변수 (PAGER, EDITOR, SHELL, ...)와 내부 쉘 변수를 대문자로 사용합니다. 다른 모든 변수 이름에는 하나 이상의 소문자가 포함되어야합니다. 이 규칙은 실수로 환경 및 내부 변수를 무시하지 않도록합니다.
Chris Down

2

필자는 비슷한 문제를 해결하기 위해 스크립트를 작성했다. "배포"라고 불렀다 ( 도움말 메시지와 함께 스크립트 또는 파일 의 메인 코드를 읽 거나 패키지로 다운로드 할 수 있음 ). 그것에서 설명 :

배포 -여러 CD에 패키지 모음 배포 (특히 APT와 함께 사용하기에 적합)

설명 :`배포 '프로그램은 패키지 모음을 배포하기위한 CD 세트 작성과 관련된 작업을보다 쉽게 ​​만듭니다. CD 파일 시스템 배치 (다량의 패키지를 여러 디스크로 분할 등), APT (인덱싱)에서 사용할 콜렉션 준비, ISO 이미지 작성 및 디스크 기록 등의 작업이 포함됩니다.

초기 배포 컬렉션에 대한 정기적 인 업데이트는`배포 '를 통해 발행 할 수 있습니다.

전체 단계를 여러 단계로 수행합니다. 한 단계에서 원본 파일에 대한 심볼릭 링크를 사용하여 furure 디스크 "레이아웃"을 생성하므로 향후 디스크 트리를 개입시키고 변경할 수 있습니다.

사용법에 대한 자세한 내용은 스크립트 또는 소스 코드를 통해 인쇄 된 도움말 메시지를 참조하십시오.

더 까다로운 사용 사례를 염두에두고 (원래 기록 된 파일 모음에 "diff"(추가 된 새 파일 세트)로 업데이트를 발행 함) 추가 초기 단계 인 "고정"이 포함됩니다. "파일 콜렉션의 현재 상태 (간단하게하기 위해 콜렉션 상태를 저장하기위한 특수 작업 장소에서 심볼릭 링크를 통해 원래 파일 콜렉션을 복제하여이를 수행합니다. 그런 다음 나중에는 향후 파일 모음의 현재 상태와이 저장된 상태간에 차이를 만들 수 있습니다. 따라서이 기능이 필요하지 않더라도이 초기 단계 인 AFAIR를 건너 뛸 수 없습니다.

또한 복잡한 트리를 잘 처리하는지 또는 파일의 일반 (한 레벨) 디렉토리 만 분할 해야하는지 여부는 확실하지 않습니다 (몇 년 전에 썼습니다). (도움말 메시지 또는 소스 코드를 확인하십시오. 시간이 좀 걸리면 조금 나중에 살펴 보겠습니다.)

APT 관련 항목은 선택 사항이므로 필요하지 않은 경우 APT에서 사용할 패키지 모음을 준비 할 수 있다는 점에주의하십시오.

물론 관심이 있으시면 언제든지 다시 작성하거나 개선을 제안하십시오.

( 패키지 에는 위에 링크 된 Git 저장소에서 제시된 코드 목록에 적용되지 않은 추가 유용한 패치가 포함되어 있습니다!)


나는 한 발표 --among 다른 일을 - 코드 발췌에서 distribute필수적인 작업이 여기에 대해 질문이 해결한다.
imz-Ivan Zakharyaschev

2

우리는이 과제의 본질이 실제로 매우 단순하다는 것을 잊지 말아야합니다. Haskell에 대한 튜토리얼에서 볼 수 있듯이 (이 작업을위한 솔루션의 작업을 중심으로 작성되었으며 점진적으로 개선되었습니다)

이제 프로그램이 어떻게 작동하고 의사 코드로 표현되는지에 대해 잠시 생각해 봅시다.

main = Read list of directories and their sizes.
       Decide how to fit them on CD-Rs.
       Print solution.

합리적으로 들리나요? 나는 그렇게 생각했다.

인생을 조금 단순화하고 지금은 프로그램 외부의 디렉토리 크기 (예 : " du -sb *")를 계산하고 stdin에서이 정보를 읽겠다고 가정 해 봅시다 .

( 히치하이커 안내서에서 Haskell까지, 1 장 )

또한 귀하의 질문에 따라 결과 디스크 레이아웃을 조정 (편집) 한 다음 도구를 사용하여 구울 수 있습니다.

파일 모음을 분할하기 위해 Haskell 튜토리얼에서 간단한 프로그램 변형을 재사용 (적응 및 재사용) 할 수 있습니다.

불행하게도,에 내가 다른 대답 여기에 언급했다고 도구 , 필수 분할 작업의 단순성이의 사용자 인터페이스의 복잡성과 bloatedness가 일치하지 않습니다 그것은 여러 가지 작업을 결합하기 위해 작성 되었기 때문에 (; 단계에서 수행하지만, 그러나 여전히 내가 생각할 수있는 가장 깨끗한 방식으로 결합되지 않았습니다).distributedistribute

코드를 사용하는 데 도움이되도록 다음은 파일 모음을 분할하는이 "필수"작업을 수행 하는 bash 코드 distribute( 380 행 ) 에서 발췌 한 내용입니다 .

# Splitting:

function splitMirrorDir() {
  if [[ ! -d "$THIS_BASES_DIR/$BASE/$type" ]]; then
    echo $"No base fixed for $type" >&2
    exit 1
  fi

  # Getting the list of all suitable files:
  local -a allFiles
  let 'no = 0' ||:
  allFiles=()
  # no points to the next free position in allFiles
  # allFiles contains the constructed list
  for p in "$THIS_BASES_DIR/$BASE/$type"/*.rpm; do
      if [[ ! -e "$p" ]]; then
      # fail on non-existent files
      echo $"Package file doesn't exist: " "$p" >&2
      return 1 
      fi
      if [[ "$ONLY_REAL_FILES" == "yes" && ! -f "$p" ]]; then
      continue
      fi
      if [[ "$DIFF_TO_BASE" ]]; then
          older_copy="$DIFF_TO_BASE/$type/${p##*/}" # using shell param expansion instead of `basename' to speed up
          if [[ -h "$older_copy" || -a "$older_copy" ]]; then
          continue
      fi
      fi
      allFiles[$(( no++ ))]="$p"
  done
  readonly -a allFiles

  # Splitting the list of all files into future disks:
  # 
  local -a filesToEat allSizes
  let 'no = 0' ||:
  filesToEat=()
  allSizes=($(getSize "${allFiles[@]}"))
  readonly -a allSizes
  # allSizes contains the sizes corrsponding to allFiles
  # filesToEat hold the constructed list of files to put on the current disk
  # no points to the next free position in filesToEat
  # totalSize should hold the sum of the sizes 
  #  of the files already put into filesToEat;
  #  it is set and reset externally.
  for p in "${allFiles[@]}"; do 
      if (( totalsize + ${allSizes[$(( no ))]} > CDVOLUME )); then
      eatFiles "${filesToEat[@]}"
          filesToEat=()
          finishCD
      startTypedCD
    fi
      let "totalsize += ${allSizes[$(( no ))]}" ||:
      filesToEat[$(( no++ ))]="$p"
  done
  eatFiles "${filesToEat[@]}"
}

function eatFiles() {
    #{ oldIFS="$IFS"; IFS=$'\n'; echo "$FUNCNAME: args: " "$*" | head >&2;  IFS="$oldIFS"; }
    zeroDelimited "$@" | xargs -0 --no-run-if-empty \
    cp -s \
    --target-dir="$THIS_LAYOUTS_DIR/cd$(( cdN ))/$PREFIX/$type$DOT_SUFFIX"/ \
    --
}

function startTypedCD() {
#  set -x
  mkdir -p "$THIS_LAYOUTS_DIR/cd$(( cdN ))/$PREFIX/$type$DOT_SUFFIX"
  start_action $" %s with %s" "$(( cdN ))" "$type"
#  set +x
}

function finishCD() {

( 454 행 이후에 더 읽으십시오 )

eatFiles함수는 미래 디스크의 레이아웃을 나뭇잎이 실제 파일에 대한 심볼릭 링크 인 트리로 준비합니다. 따라서 굽기 전에 레이아웃을 편집 할 수 있어야합니다. 이 mkisofs유틸리티에는 심볼릭 링크를 따르는 옵션이 있으며 실제로 mkiso기능 코드에 사용됩니다 .

제시된 스크립트 (물론 필요에 따라 다시 쓰고 쓸 수 있음)는 가장 간단한 아이디어를 따릅니다. 파일의 크기 (또는 더 정확하게는 패키지의 경우 distribute)를 나열된 순서대로 합산하는 것입니다. 재 배열하지 마십시오.

"하스켈에 대한 히치하이커 안내서"는 최적화 문제를보다 심각하게 고려하여 파일을 디스크에 더 잘 맞추기 위해 (그리고 더 적은 디스크를 필요로하기 위해) 파일을 스마트하게 재배치하려고 시도하는 프로그램 변형을 제안합니다.

충분한 예비가 이미 있습니다. CD를 싸서 갑시다.

당신이 이미 알고 있듯이, 우리의 문제는 고전적인 문제입니다. 그것은이라고합니다 "배낭 문제" ( 그것을 구글 은 그것이 이미 모르는 경우. 더 100,000 이상의 링크가 있습니다).

탐욕스러운 해결책부터 시작합시다 ...

( 3 장 이상에서 더 읽으십시오 .)

다른 스마트 도구

데비안은 distributewrt 패키지 모음 보다 똑똑한 배포 CD를 만드는 도구를 사용한다고 들었 습니다. 결과는 패키지 간 종속성을 염려하고 패키지 모음을 만들려고 시도하기 때문에 더 좋습니다 . 첫 번째 디스크는 종속성으로 닫힙니다. 즉, 첫 번째 디스크의 패키지는 다른 디스크의 패키지를 필요로하지 않아야합니다 (또는 적어도 그러한 종속성의 수를 최소화해야합니다).


1

backup2l은이 작업을 많이 수행 할 수 있습니다. 패키지를 직접 사용하지 않더라도 스크립트 아이디어를 얻을 수 있습니다.


0

rar아카이버는 자동으로이가있는 특정 크기의 덩어리들로 만들어 보관 분할하도록 지시 할 수 있습니다 -vsize플래그.

지정한 디렉토리 트리를 foo500MB의 덩어리로 아카이브
rar a backup.rar -v500m foo/


2
왜 희귀 한 것보다? tar (+ bz2) + split은 * nix의 기본 접근 방식입니다.
rvs

"물린 크기의 나무"는 rar각 "부품"을 자체 디렉토리에 다시 압축을 풀지 않는 한 소리가 나지 않습니다. 물론 부품이 그렇게 설계되지 않았고 파일 경계에서 분할되지 않기 때문에 작동하지 않습니다.
MattBianco

1
tar+ split와 같은 결과 를 제공하는 도구에 대해 이야기한다면 dar도 있습니다 . 관련 기능에 대한 참고 사항은 다음과 같습니다. "(SLICES) 번호와 크기에 관계없이 여러 이동식 미디어로 아카이브를 분할 할 수 있도록 설계되었습니다." tar+ 와 비교 split하면 아카이브 된 파일에 쉽게 액세스 할 수 있다고 가정합니다. (BTW에는 distribute"차등 백업"및 "디렉토리 트리 스냅 샷" 과 유사한 기능이 있지만 결과는 디렉토리가있는 ISO가 아니라 특수 형식이라는 점이 마음에 들지 않을 수 있습니다.
imz-Ivan Zakharyaschev
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.