綾小路龍之介の素人思考

rsyncでディレクトリの内容を同期する

rsyncは高機能なミラーリングのツール。でも、ミラーリング以外にもさまざまな条件を付けて2つのディレクトリの内容のコピーが可能だ。diffとmvやcpでやっていた複雑な仕事をrsyncに任せれば仕事が速く終わって、遊べる時間が増える。


目次


1.1 [rsync] ディレクトリ間の同期(OR)

ディレクトリhogeとディレクトリhageがあって、hageさんとhogeさんがそれぞれのディレクトリの内容を変更する。この時2つのディレクトリの内容のORを取りたい。同じファイルを編集されると困るけど。

$ diff hoge/ hage/
$ rsync -avz hoge/ hage/
$ diff hoge/ hage/
$ rsync -avz hage/ hoge/
$ diff hoge/ hage/

2回rsyncして--deleteしないことがキモ。始めにこんなかんじだったのが、

+- hage/
   | a.txt
   \ A.txt
+- hoge/
   | a.txt
   \ B.txt

1回目のrsyncで、こんな感じになり、

+- hage/
   | a.txt
   | A.txt
   \ B.txt
+- hoge/
   | a.txt
   \ B.txt

2回目のrsyncで、こんな感じになる

+- hage/
   | a.txt
   | A.txt
   \ B.txt
+- hoge/
   | a.txt
   | A.txt
   \ B.txt

ということで、同期できたことになる。今回の想定はhage/とhoge/に共通に存在するa.txtは全く同じ物とする。


1.2 [rsync] HDDを大容量に変えた後のHDD

状況としてはこうだ。古いHDDの容量は160GB、これがいっぱいになったので新しいHDD(容量500GB)にその内容をcpでコピーして、以降は新しいHDDで仕事をしていた。500GBのHDDもいっぱいになったところで、160GBのHDDがあったことを思い出してこの内容を削除して使おうとした。しかし、160GBのHDDの内容は500GBのHDDに内容をコピーしたタイミング以降にいくつかのファイルやらディレクトリが追加され、全てを削除してしまうと追加されたファイルやディレクトリまで削除してしまうことになる。500GBのHDDにコピーが取られている、もしくは500GBのHDDで内容を新しくされたもの、これらを160GBのHDDから削除したい。

まずはマウント。500GBのHDDは/dev/hdc1、160GBのHDDは/dev/hdd1にあるとする。

# mount /dev/hdc1 /mnt/hdc1
# mount /dev/hdd1 /mnt/hdd1

今回は160GBのHDD(/mnt/hdd1)から500GBのHDD(/mnt/hdc1)に向けてのコピー。rsyncを--dry-run(-n)してみる。ドライランのオプションはrsyncのやることを表示してくれるが、実際に仕事は行われないオプション。つまり、テストのためのオプション。

# rsync -avv --exclude "foo/" -n /mnt/hdd1 /mnt/hdc1
huga.txt
hoge/hoga.txt is uptodate
hoge/hogo.txt
  1. 2つのディレクトリの同期をとるには

このようにテストしてみると、完全に同期が取れているものに関しては'~ is uptodate'のようにして表示してくれる。つまり、今回削除したいファイルは'is uptodate'の付いたファイルだ。このまま-nを除いてrsyncを走らせるとis uptodateの付かなかったファイルに関して/mnt/hdc1にコピーが行われる。そのため、このままrsyncを走らせてはいけない。今回の目的は送信側のファイルを削除することにある。rsyncのmanページで送信側のファイルを削除するオプションを探す。

一通り見てみた限りでは、受信側のファイルを削除するオプションはあるが、送信側のファイルを削除するオプションは無い。送信側と受信側を入れ替えて削除オプションを効かせてみればどうかとも思ったが、どの削除系オプション(--delete)を試してみてもうまいこと篩い分け出来ない。そこで、先に述べたis uptodateの付いたファイルのみを抜き出すためだけにrsyncを使い、is uptodateの情報を元に目的のファイルを削除するシェルスクリプトを書いてみる。

まずは削除対象となるファイルの抜き出し。rsyncでis uptodateと判断されたファイルの名前をrm.txtにリダイレクト。rm.txtは削除対象のファイル名が1行おきにリストされたファイルになる。

# rsync -avv --exclude "foo/" -n hdd1/ hdc1/ | grep --regex ' is uptodate$' | sed "s/ is uptodate$//" > rm.txt
  1. Command Technica:はじめてrsyncを使う方が知っておきたい6つのルール (1/2) - ITmedia エンタープライズ
  2. Command Technica:はじめてrsyncを使う方が知っておきたい6つのルール (2/2) - ITmedia エンタープライズ
  3. rsync

ファイル名を元にrmしていく際にはrmに正しく引数が渡されるようにしなければならない。つまり、正しくエスケープしなければならない。そのためにいったんechoコマンドで引数が正しく渡されるかどうか確認。エスケープの指針として、シングルコーテーションで括るが、シングルコーテーションで括ってもエスケープできないファイル名自体に含まれるシングルコーテーションについてはシングルコーテーションで括る前に'"'"'で置換しておく。バッドノウハウであることは重々承知だが、これでよい。其の後にこれを走らせ、元の削除対象リストの内容と比較する。

# cat rm.txt | sed "s/'/'\"'\"'/g" | sed "s/$/\'/" | sed "s/^/echo \'/" > rm2.sh
# sh rm2.sh > rm2.txt
# diff rm.txt rm2.txt
  1. shellscripts - ReoGlobalBrain:PukiWikiAnnex
  2. §10. このファイル消せますか?(rm, bash, シェル) その3
  3. i-nodeを指定してファイルを削除したい(それでも削除できないやばいファイルができてしまった) - 針と糸
  4. How to: Linux / UNIX Delete or Remove Files With Inode Number
  5. Linux : How to delete file securely

出来たシェルスクリプト(rm2.sh)を走らせた結果(rm2.txt)と元の削除対象リスト(rm.txt)が同じならば、上の指針で行ったエスケープ処理が成功しechoコマンドに正しく引数が渡されたことになる。linuxの場合、引数を渡すコマンドが違っていても、エスケープされた引数を解析してコマンドに渡すまでの仕事は共通のシェル(ここではbash)がしてくれるので、rmに渡す引数のエスケープ処理とechoに渡すエスケープ処理は同じでよいはずだ。そこで、rm2.shを作ったコマンドラインを編集してrmするようなシェルスクリプトを生成する。

# cat rm.txt | sed "s/'/'\"'\"'/g" | sed "s/$/\'/" | sed "s/^/rm -- \'/" > rm3.sh

ここで生成されたシェルスクリプト(rm3.sh)を/mnt/hdd1の中で走らせれば目的が達成される。最後の確認としてviで内容を見ておこう。

# vi rm3.sh
# cd /mnt/hdd1
# sh ~/rm3.sh

さて、このようにしてファイルを削除することは出来るが、空になったディレクトリを削除することは出来ない。安全かつ再帰的に空になったディレクトリを削除する良い方法は、削除したいディレクトリの親ディレクトリの中でfindとrmdirを使うことだ。rmdirは引数として与えられたディレクトリの中味が無い場合のみそのディレクトリを削除する。引数がファイルだったり中味のあるディレクトリだった場合には削除せずエラー終了する。そのため、findからもらった引数にファイル名や中味のあるディレクトリが含まれていてもこれらの場合は何もせずに終了してくれるので、rmdirの前に引数チェックしないで使えるため便利である。

# cd /mnt/hdd1
# find -print0 | xargs -0 rmdir -p
  1. findのexecが便利 - マツモブログ
  2. 【 rmdir 】 ディレクトリを削除する:ITpro
  3. ◇ディレクトリとファイルの削除◇初心者のためのLinuxサーバー構築講座☆お便利.com☆

これで、目的が達成できたはずだ。/mnt/hdd1の中から、/mnt/hdc1と同期の取れたファイルやディレクトリは削除された。


サイトマップ

  1. CSS > Webサイトのレイアウトの話
  2. DVDリッピングしてaviファイルにするときの計算方法
  3. Debian > インストールメモ
  4. Memo > One Line Diary
  5. Memo > To-Doリスト
  6. Memo > iswebの自動挿入広告の文字コードに関する考察
  7. Memo > リンクとメモ
  8. Memo > 物理屋の独り言
  9. Misc > High Performance Computing(HPC)
  10. PC過去の遺物集
  11. Perl > 1行スクリプト覚書 with Active Perl
  12. Perl > Perl実験室でWeb雑考
  13. Perl > XML::TreePPでXMLサイトマップファイルを生成
  14. Perl > e.cgi のページ ProjectRotation8
  15. Perl > クエリを連想配列で受け取るスマートな方法
  16. Perl > サーバーにアップロードしたcgiのエラーチェック
  17. Perl > ブリコラージュ的 cgi
  18. Programing > プログラムの素人が不思議に思ったこと
  19. Services > Gmail Tips
  20. Services > YourFileHostダウンローダ
  21. Services > twitterはじめました。
  22. Tech > MathMLを使ってみる
  23. Tech > Windows 2000 Professional でLaTeX組版システムを使う
  24. Tech > coLinuxの導入
  25. Tech > サイトのミラーリング
  26. Terapadで作るLaTeX統合環境
  27. Tools > Opera > 設定の諸々
  28. Tools > bashのメモ
  29. Tools > lit2ptoのページ
  30. Tools > vimの設定とtips
  31. Tools > よく使う機能のメモと設定のメモ
  32. VMware > ホストOSがWindows XP Home SP2でゲストOSがVine Linux 4.1
  33. Vine > SSHの暗号化経路を経由してSambaサーバの共有ディレクトリをマウント
  34. Vine Linux > LaTeXでpdf文書作成
  35. Vine Linux > Libretto L1に載せる
  36. Vine Linux > SSH関係の諸々メモ
  37. Vine Linux > サーバを立てたときのメモ
  38. Vine Linux > ソフトウェアRAID
  39. Vine Linux > デスクトップとして使う場合に必要な設定
  40. Wanderlust > inter7でIMAP4
  41. Web Etcetera > サーバー上でファイルを直接編集することについて
  42. Web Etcetera > 検索エンジンが自分のサイトをどのように認識しているか
  43. Web Etcetera > 無料ホームページスペースの広告削除は真か偽か
  44. Winamp > StreamRipperで全自動リッピング
  45. Winamp > タスクマネージャを使って目覚まし時計
  46. Windows > robocopyでフォルダ間同期
  47. Windows > 手動でコーデックをインストールする
  48. gnuplotのプロットギャラリー
  49. rsyncでディレクトリの内容を同期する
  50. wgetのメモ
  51. ネットワーク上にメモ帳を置く
  52. ハードウェア > HDDの再利用
  53. ハードウェア > 安定で快適なマシンはハードから
  54. ブリコラージュ的メールマガジン一括登録解除方法
  55. 初めに
  56. 情報基礎演習UNIX
  57. 窓たちと正く付き合うにはショートカットキーから

コメント


pin

[PR]ÓeOȂœ܂񂩁H:S19@tŌtقW