大きなディレクトリツリーを指定されたサイズのチャンクに分割しますか?


11

光ディスクにバックアップしたいディレクトリツリーがあります。残念ながら、これは1つのディスクのサイズを超えます(約60GBです)。このツリーをハードリンクなどの適切なサイズのチャンクに分割するスクリプトを探しています(オリジナルはそのままにしておきます)。次に、これらの一口サイズのツリーをバックアッププロセスにフィードします(PAR2の冗長性を追加するなど)。

派手なスクリプトではありませんが、既に行われているようです。提案?

(ファイルの書き込みが完了する前に、さらに多くのことを実行したいので、1つのステップでスパンと書き込みを行うことはできません。)


ブルーレイライターの取得を検討しましたか?
bsd

2
DVDメディアは信頼できません...外付けドライブ、Carboniteのようなオンラインバックアップ、またはメディアを書き込む場合は何らかのpar2保護を使用することをお勧めします。
アーロンD.マラスコ

回答:


7

これのために設計されたアプリケーションが存在します: dirsplit

それは通常、cdrkitまたはdirsplitパッケージに住んでいます。

K3bまたはその他のGUIソフトウェアでDVDを簡単に作成するためのリンクを含む、すぐに使用できるフォルダーを作成できます


これは本当にうまくいきました。Ubuntuでは、genisoimageパッケージでそれを見つけました。
nograpes 14


2

私はかつて同じような目的で醜いスクリプトを作成しました。それは単なる策略ですが、私がそれを書いたとき、私は実行時間やかわいさを気にしませんでした。同じコンセプトの「製品化された」バージョンは他にもあると思いますが、アイデアや何かをハッキングを開始したい場合は、こちらをご覧ください(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"

私はその結果をsambaを介してWindowsホストに共有し、そこからディスクを書き込んだと思います。上記を変更せずに使用する場合は、mkisofsシンボリックリンクを解決するアーカイバまたは別のアーカイバを使用することをお勧めします。


スクリプトにいくつかの変更を加えて、ファイル名の特殊文字(空白、最初のダッシュとドット、\[?*)に対処しました。推奨される読み物:ls$ VARと$ {VAR} の出力を解析せず、引用するかしないか。結果のスクリプトはテストしていないことに注意してください。私の変更の1つを理解していない場合は、遠慮なく質問してください。
Gilles「SO-邪悪なことをやめなさい」

@ギレス:私は2008年以来たくさん読んでいます;-)スクリプトをより一般的にするための変更は良いです。(ただし、[とは対照的にの導入は嫌いtestです)...
MattBianco

これらの変数のほとんどは小文字にする必要があります。慣例により、環境変数(PAGER、EDITOR、SHELLなど)と内部シェル変数を大文字にします。他のすべての変数名には、少なくとも1つの小文字を含める必要があります。この規則により、環境変数と内部変数を誤って上書きすることが回避されます。
クリスダウン

2

私はかつて、同様の問題を解決するためにスクリプトを作成しました。これを「配布」と呼びました(スクリプトのメインコードまたはヘルプメッセージファイルを読むか、パッケージとしてダウンロードできます)。その説明から:

配布 -パッケージのコレクションを複数のCDで配布します(特に、APTで将来使用する場合に適しています)

説明:「distribute」プログラムを使用すると、パッケージのコレクションを配布するためのCDセットの作成に関連するタスクを簡単に実行できます。タスクには、CDファイルシステムのレイアウト(大量のパッケージを複数のディスクに分割するなど)、APT(インデックス作成)で使用するためのコレクションの準備、ISOイメージの作成、およびディスクの記録が含まれます。

最初に配布されたコレクションに対する定期的な更新は、「配布」の助けを借りて発行できます。

プロセス全体をいくつかの段階で実行します。ある段階では、元のファイルへのシンボリックリンクを使用して、furureディスクの「レイアウト」を作成します。これにより、将来のディスクツリーに介入して変更できます。

その使用法の詳細は、スクリプトによって(またはソースコードを調べることによって)印刷されるヘルプメッセージで読むことができます。

これは、よりトリッキーなユースケースを念頭に置いて作成され(更新を「diff」(追加された新しいファイルのセット)として最初に記録されたファイルのコレクションに発行する)、1つの追加の初期段階、つまり「修正"ファイルのコレクションの現在の状態(簡単にするために、コレクションの状態を保存するための特別な作業場所で、シンボリックリンクを使用して元のファイルのコレクションを複製することでこれを行います。その後、しばらくしてからファイルのコレクションの将来の現在の状態とこの保存された状態の間に差分を作成することができます)。したがって、この機能は必要ないかもしれませんが、この最初の段階であるAFAIRをスキップすることはできません。

また、複雑なツリーを適切に処理するのか、それともファイルのプレーン(1レベル)のディレクトリのみを分割することになっているのか、私は(数年前に書きました)今はわかりません。(確認のため、ヘルプメッセージまたはソースコードを確認してください。少し時間がたってから、これも調べます。)

APT関連のものはオプションであるため、必要がない場合は、APTで使用するパッケージコレクションを準備できることに注意してください。

もちろん、興味を持った場合は、自由に書き換えたり、改善を提案したりしてください。

パッケージには、上記のGitリポジトリで提示されたコードリストに適用されていない追加の有用なパッチが含まれていることに注意しください!)


私は、とりわけ、ここで尋ねられた重要なタスクを解決するコードの抜粋を提示しましdistributeた。
imz-Ivan Zakharyaschev 2011年

2

タスクの本質が実に単純であることを忘れてはなりません。Haskellのチュートリアルに記載されているように(これは、このタスクのソリューションの作業手順を中心に書かれており、徐々に改良されています)

ここで、プログラムがどのように動作し、それを疑似コードで表現するかについて少し考えてみましょう。

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

合理的に聞こえますか?私はそうだと思いました。

私たちの生活を少し単純化して、今のところ、プログラムの外のどこかで(たとえば、 " du -sb *"を使用して)ディレクトリサイズを計算し、この情報をstdinから読み取ると仮定します。

HitchhikersガイドからHaskellへ、第1章

(さらに、あなたの質問では、結果のディスクレイアウトを微調整(編集)し、ツールを使用してそれらを書き込むことができます。)

ファイルコレクションを分割するためのHaskellチュートリアルのプログラムの単純なバリアントを再利用(適応および再利用)できます。

残念ながら、ここで別の回答述べdistributeツールでは、重要な分割タスクのシンプルさは、ユーザーインターフェースの複雑さと肥大さには対応していませんdistribute(複数のタスクを組み合わせるように記述されているため、段階的に実行されますが、しかし、私が今考えることができる最もきれいな方法ではまだ結合されていません)。

そのコードの使用を支援するために、ファイルのコレクションを分割するこの「重要な」タスクを実行するのに役立つdistribute380行目)のbashコードからの抜粋を次に示します。

# 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ています。再配置は行いません。

"Hitchhikers guide to Haskell"は最適化の問題をより真剣に受け止め、ファイルをより適切に再配置してディスクに収まるように(そして必要なディスクが少なくなるように)プログラムのバリエーションを提案します。

すでに十分な予備知識。いくつかのCDをパックしましょう。

すでにご存じかもしれませんが、私たちの問題は古典的な問題です。これは「ナップサックの問題」と呼ばれます (それが何であるかまだわからない場合は、グーグルで確認してください。100000以上のリンクがあります)。

貪欲な解決策から始めましょう...

第3章でさらに詳しく読んでください。)

その他のスマートツール

DebianはdistributeパッケージのwrtコレクションよりもスマートなディストリビューションCDを作成するためのツールを使用することも聞かれました。パッケージ間の依存関係を考慮し、取得するパッケージのコレクションを作成しようとするため、結果はより良いです最初のディスクは依存関係の下で閉じられました。つまり、最初のディスクからのパッケージは別のディスクからのパッケージを必要としません(または、少なくとも、そのような依存関係の数を最小限に抑える必要があります)。


1

backup2lはこの作業の多くを実行できます。パッケージを直接使用しなくても、スクリプトのアイデアが得られる場合があります。


0

rarアーカイバは、自動的にそれが持つ特定のサイズのチャンクに作成したアーカイブに分割するように指示することができる-vsizeフラグを。

指定したディレクトリツリーfooを、たとえば500メガバイトのチャンクに指定してアーカイブする
rar a backup.rar -v500m foo/


2
なぜRARよりも?tar(+ bz2)+ splitは* nixのよりネイティブなアプローチです。
rvs '28

「バイトサイズのツリー」はrar、各「パーツ」を独自のディレクトリに再度解凍しない限り、まったく同じように聞こえません。パーツはそのように設計されておらず、ファイルの境界で分割されていないため、もちろん機能しません。
MattBianco

1
tar+のsplitような結果が得られるツールの場合、darもあります。関連する機能についてのメモは次のとおりです。「(SLICES)アーカイブの数やサイズに関係なく、アーカイブを複数のリムーバブルメディアに分割できるように設計されています。」tar+ と比較するとsplit、アーカイブされたファイルにアクセスする簡単な方法がいくつかあると思います。(ちなみに、distribute「DIFFERENTIAL BACKUP」と「DIRECTORY TREE SNAPSHOT」のような機能もありますが、結果が特殊な形式であり、dirツリーを含むISOではない場合があります。)
imz-Ivan Zakharyaschev
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.