Chia cây thư mục lớn thành các khối kích thước quy định?


11

Tôi có một cây thư mục mà tôi muốn sao lưu vào đĩa quang. Thật không may, nó vượt quá kích thước của bất kỳ một đĩa nào (khoảng 60 GB). Tôi đang tìm kiếm một kịch bản có thể chia cây này thành các đoạn có kích thước phù hợp với các liên kết cứng hoặc không có gì (không để nguyên bản gốc). Sau đó tôi có thể cho những cây có kích thước cắn này vào quá trình sao lưu (thêm dự phòng PAR2, v.v.).

Nó không phải là một kịch bản ưa thích, nhưng có vẻ như nó đã được thực hiện. Gợi ý?

(Khoảng cách và viết trong một bước là không nên vì tôi muốn làm nhiều thứ hơn trước khi các tệp bị đốt cháy.)


Bạn đã xem xét nhận được một nhà văn Bluray?
bsd

2
Phương tiện DVD không đáng tin cậy ... Tôi muốn giới thiệu một ổ đĩa ngoài, sao lưu trực tuyến như Carbonite hoặc nếu ghi phương tiện, hãy sử dụng một số par2biện pháp bảo vệ.
Aaron D. Marasco

Câu trả lời:


7

Có tồn tại một ứng dụng được thiết kế cho việc này: dirsplit

Nó thường sống trong cdrkithoặc dirsplitgói.

Nó có thể tạo các thư mục sẵn sàng sử dụng với các liên kết để dễ dàng tạo DVD bằng K3b hoặc phần mềm GUI khác


Điều này làm việc thực sự tốt. Trong Ubuntu tôi tìm thấy nó trong genisoimagegói.
nogpes


2

Tôi đã từng làm một kịch bản xấu xí cho một mục đích tương tự. Nó chỉ là một loại bùn, nhưng khi tôi viết nó, tôi không quan tâm đến thời gian thực hiện hay sự xinh đẹp. Tôi chắc chắn có nhiều phiên bản "được sản xuất hóa" của cùng một khái niệm xung quanh, nhưng nếu bạn muốn có một số ý tưởng hoặc một cái gì đó để bắt đầu hack, thì đây (hãy thực hiện vào năm 2008, vì vậy hãy tự chịu rủi ro!): - )

#!/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"

Tôi nghĩ rằng tôi đã có kết quả được chia sẻ thông qua samba đến một máy chủ lưu trữ cửa sổ ghi đĩa từ nó. Nếu bạn sử dụng các thay đổi ở trên, bạn có thể muốn sử dụng mkisofshoặc một trình lưu trữ khác giải quyết các liên kết tượng trưng.


Tôi đã thực hiện một vài thay đổi cho tập lệnh của bạn để đối phó với các ký tự đặc biệt trong tên tệp (khoảng trắng, dấu gạch ngang ban đầu và dấu chấm, \[?*). Đọc gợi ý: không phân tích đầu ra của ls , $ VAR so với $ {VAR} và để trích dẫn hoặc không trích dẫn . Lưu ý rằng tôi đã không kiểm tra tập lệnh kết quả. Nếu bạn không hiểu một trong những thay đổi của tôi, vui lòng hỏi.
Gilles 'SO- ngừng trở thành ác quỷ'

@Gilles: Tôi đã đọc rất nhiều từ năm 2008 ;-) Thay đổi để làm cho kịch bản chung chung hơn là tốt. (Tuy nhiên, tôi không thích phần giới thiệu [trái ngược với test) ...
MattBianco

Bạn nên viết thường hầu hết các biến đó. Theo quy ước, chúng tôi viết hoa các biến môi trường (PAGER, EDITOR, SHELL, ...) và các biến shell nội bộ. Tất cả các tên biến khác phải chứa ít nhất một chữ cái viết thường. Quy ước này tránh vô tình ghi đè các biến môi trường và nội bộ.
Chris Xuống

2

Tôi đã từng viết một kịch bản để giải quyết vấn đề tương tự - Tôi gọi nó là "phân phối" (bạn có thể đọc mã chính của tập lệnh hoặc tệp có thông báo trợ giúp hoặc tải xuống dưới dạng gói ); từ mô tả của nó :

phân phối - Phân phối bộ sưu tập các gói trên nhiều đĩa CD (đặc biệt tốt cho việc sử dụng trong tương lai với APT)

Mô tả: Chương trình 'phân phối' giúp thực hiện các tác vụ liên quan đến việc tạo bộ đĩa CD để phân phối bộ sưu tập các gói dễ dàng hơn. Các tác vụ bao gồm: bố trí hệ thống tập tin CD (chia số lượng lớn các gói thành nhiều đĩa, v.v.), chuẩn bị bộ sưu tập để APT sử dụng (lập chỉ mục), tạo hình ảnh ISO và ghi đĩa.

Các cập nhật định kỳ cho bộ sưu tập được phân phối ban đầu có thể được phát hành với sự trợ giúp của 'phân phối'.

Nó thực hiện toàn bộ quá trình trong một số giai đoạn: ở một giai đoạn, nó tạo ra "bố cục" đĩa furure bằng cách sử dụng các liên kết tượng trưng cho các tệp gốc - để bạn có thể can thiệp và thay đổi cây đĩa trong tương lai.

Các chi tiết về cách sử dụng của nó có thể được đọc trong thông báo trợ giúp được in bởi tập lệnh (hoặc bằng cách xem mã nguồn).

Nó được viết với một trường hợp sử dụng phức tạp hơn trong tâm trí (phát hành các bản cập nhật dưới dạng "diff" - tập hợp các tệp mới được thêm vào - vào bộ sưu tập các tệp được ghi lại ban đầu), do đó, nó bao gồm một giai đoạn ban đầu bổ sung, đó là "sửa lỗi "trạng thái hiện tại của bộ sưu tập tệp (để đơn giản, nó thực hiện điều này bằng cách sao chép bộ sưu tập tệp gốc bằng các liên kết tượng trưng, ​​ở một nơi làm việc đặc biệt để lưu các trạng thái của bộ sưu tập; sau đó, trong tương lai, nó sẽ sẽ có thể tạo khác biệt giữa trạng thái hiện tại của bộ sưu tập tệp và trạng thái đã lưu này). Vì vậy, mặc dù bạn có thể không cần tính năng này, bạn không thể bỏ qua giai đoạn ban đầu này, AFAIR.

Ngoài ra, bây giờ tôi không chắc chắn (tôi đã viết nó cách đây vài năm) liệu nó có xử lý tốt các cây phức tạp hay không hay chỉ nên chia các thư mục đơn giản (một cấp) của các tệp. (Vui lòng xem thông báo trợ giúp hoặc mã nguồn để chắc chắn; tôi cũng sẽ tìm kiếm điều này, một lát sau, khi tôi có thời gian.)

Các công cụ liên quan đến APT là tùy chọn, vì vậy đừng chú ý rằng nó có thể chuẩn bị các bộ sưu tập gói được APT sử dụng nếu bạn không cần thứ này.

Tất nhiên, nếu bạn cảm thấy hứng thú, hãy viết lại theo nhu cầu của bạn hoặc đề xuất cải tiến.

(Xin lưu ý rằng gói bao gồm các bản vá hữu ích bổ sung không được áp dụng trong danh sách mã được trình bày tại repo Git được liên kết ở trên!)


Tôi đã trình bày - nhiều thứ khác - đoạn trích từ distributeđó giải quyết nhiệm vụ thiết yếu được hỏi về đây.
imz - Ivan Zakharyaschev

2

Chúng ta không nên quên rằng bản chất của nhiệm vụ thực sự khá đơn giản; như được đưa vào một hướng dẫn về Haskell (được viết xung quanh hoạt động thông qua giải pháp cho nhiệm vụ này, được tinh chỉnh dần dần)

Bây giờ chúng ta hãy suy nghĩ một chút về cách chương trình của chúng tôi sẽ vận hành và thể hiện nó bằng mã giả:

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

Nghe có vẻ hợp lý? Tôi cũng nghĩ vậy

Chúng ta hãy đơn giản hóa cuộc sống của mình một chút và giả sử bây giờ chúng ta sẽ tính kích thước thư mục ở đâu đó bên ngoài chương trình của chúng ta (ví dụ: với " du -sb *") và đọc thông tin này từ stdin.

(từ hướng dẫn của Hitchhikers đến Haskell, Chương 1 )

(Bổ sung, trong câu hỏi của bạn, bạn muốn có thể điều chỉnh (chỉnh sửa) bố cục đĩa kết quả, sau đó sử dụng một công cụ để ghi chúng.)

Bạn có thể sử dụng lại (điều chỉnh và sử dụng lại) một biến thể đơn giản của chương trình từ hướng dẫn Haskell đó để chia bộ sưu tập tệp của bạn.

Thật không may, trong những distributecông cụ mà tôi đã đề cập ở đây trong câu trả lời khác , sự đơn giản của công việc tách quan trọng là không phù hợp bởi sự phức tạp và bloatedness của giao diện người dùng của distribute(vì nó được viết để kết hợp một số nhiệm vụ, mặc dù thực hiện theo từng giai đoạn, nhưng vẫn kết hợp không theo cách sạch nhất mà tôi có thể nghĩ đến bây giờ).

Để giúp bạn sử dụng mã của nó, đây là đoạn trích từ mã bash của distribute(ở dòng 380 ) phục vụ cho nhiệm vụ "thiết yếu" này là chia tách bộ sưu tập tệp:

# 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() {

( đọc thêm sau dòng 454 )

Lưu ý rằng eatFileshàm chuẩn bị bố trí của các đĩa trong tương lai dưới dạng cây trong đó các lá là liên kết tượng trưng đến các tệp thực. Vì vậy, nó đáp ứng yêu cầu của bạn rằng bạn sẽ có thể chỉnh sửa bố cục trước khi ghi. Các mkisofstiện ích có một tùy chọn để làm theo liên kết tượng trưng, mà thực sự được sử dụng trong mã của tôi mkisochức năng .

Kịch bản được trình bày (tất nhiên là bạn có thể lấy và viết lại theo nhu cầu của mình!) Theo ý tưởng đơn giản nhất: tổng hợp kích thước của các tệp (hoặc chính xác hơn là các gói trong trường hợp distribute) theo thứ tự chúng được liệt kê, don Không làm gì sắp xếp lại.

"Hitchhikers guide to Haskell" xem xét vấn đề tối ưu hóa nghiêm trọng hơn và đề xuất các biến thể chương trình sẽ cố gắng sắp xếp lại các tệp một cách thông minh, để chúng phù hợp hơn trên các đĩa (và yêu cầu ít đĩa hơn):

Đủ sơ bộ rồi. Hãy đi gói một số đĩa CD.

Như bạn có thể đã nhận ra, vấn đề của chúng tôi là một vấn đề cổ điển. Nó được gọi là "vấn đề về chiếc ba lô" ( google nó lên , nếu bạn chưa biết nó là gì. Có hơn 100000 liên kết).

hãy bắt đầu từ giải pháp tham lam ...

(đọc thêm trong Chương 3 và hơn thế nữa.)

Các công cụ thông minh khác

Tôi cũng được biết rằng Debian sử dụng một công cụ để tạo ra các đĩa CD phân phối thông minh hơn các distributebộ sưu tập gói của tôi: kết quả của nó đẹp hơn vì nó quan tâm đến các phụ thuộc giữa các gói và sẽ cố gắng tạo ra bộ sưu tập các gói. đĩa đầu tiên được đóng trong các phụ thuộc, nghĩa là không có gói nào từ đĩa thứ nhất yêu cầu gói từ đĩa khác (hoặc ít nhất, tôi muốn nói, số lượng phụ thuộc như vậy nên được giảm thiểu).


1

backup2l có thể làm rất nhiều công việc này. Ngay cả khi bạn không sử dụng gói trực tiếp, bạn có thể nhận được một số ý tưởng về kịch bản từ nó.


0

Người rarlưu trữ có thể được hướng dẫn tự động phân chia kho lưu trữ mà nó tạo thành các khối có kích thước cụ thể với -vsizecờ.

Lưu trữ cây thư mục đó được đặt tên foothành các khối, giả sử, 500 megabyte mỗi người bạn chỉ định
rar a backup.rar -v500m foo/


2
Hơn tại sao rar? tar (+ bz2) + split là cách tiếp cận riêng hơn cho * nix.
rvs

"Cây có kích thước cắn" nghe không giống lắm rar, trừ khi bạn giải nén lại từng "phần" vào thư mục riêng, tất nhiên sẽ không hoạt động, vì các phần không được thiết kế như vậy và không phân chia theo ranh giới tệp.
MattBianco

1
Nếu nói về công cụ mà cho tar+ split-like kết quả, sau đó cũng dar ; Đây là lưu ý về tính năng có liên quan của nó: "(SLICE) nó được thiết kế để có thể phân chia một kho lưu trữ trên một số phương tiện lưu động bất kể số lượng của chúng là gì và kích thước của chúng là gì". So với tar+ split, tôi giả sử, nó cho phép một số cách dễ dàng hơn để truy cập các tệp được lưu trữ. (BTW, nó cũng có một tính năng tương tự như distribute: "Differential Backup" & "Cây thư mục SNAPSHOT", nhưng người ta có thể không như vậy kết quả là một định dạng đặc biệt, không phải là một tiêu chuẩn ISO với một cây dir.)
imz - Ivan Zakharyaschev
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.