Opened 14 years ago
Last modified 11 years ago
#55 assigned enhancement
指定した二つのディレクトリ以下を再帰的に比較する
Reported by: | mitty | Owned by: | mitty |
---|---|---|---|
Priority: | major | Component: | coding |
Keywords: | diff,cmp,recursive | Cc: |
Description (last modified by mitty)
Attachments (1)
Change History (8)
Changed 14 years ago by mitty
comment:1 Changed 14 years ago by mitty
- Description modified (diff)
comment:2 Changed 14 years ago by mitty
- twitter:mittyorz/status/41163091010007041
mittyorz: 2つのディレクトリ以下を、再帰的に、比較するのに、diff -r以外だとどうすればいいんだろう。diffだとファイルが巨大なテキストの場合にメモリ足りなくなることがあって困る。ファイル中のどこが違っているかは知る必要が無くて、単純に違うファイルがあることだけ検出できればいい。
yshibata: @mittyorz ファイルの更新日時だけで比較するようなシェルスクリプトを書くとか...?
mittyorz: @yshibata ああいや、日付とかは違っていても良くて、バイナリ比較して違っていたら(あるいはサイズが違っていたら)、「このパス同士は違うよ」とだけ表示してくれればいいんです。バイナリファイルだけが入っているディレクトリを再帰的にdiff -rが今のところ一番良いんですが…
AknEp: @mittyorz @yshibata あれか、WEBでクロールした画像ファイルとかか。
mittyorz: @yshibata diff -uだと、巨大なファイルをdiffがテキストと判別したときに、メモリものすごく喰って途中で死ぬことがあるのでちょっと困る、と。diffに全てバイナリと見なすオプションがあれば良いんですが…
mittyorz: @AknEp @yshibata 画像はdiffはバイナリと見なすくれるのであまり問題ない感じ。中にでかいisoとかが混じっているとたまに「これテキストだよね」となって死んじゃうんです…
AknEp: @mittyorz ハッシュをDBに入れて管理するとか? (WEB屋っぽい思想
yshibata: @mittyorz @AknEp Windowsだったらそんな感じのソフト,結構あると思うんだけど,Linuxだとわからないなぁ...(あれ,そもそもLinuxじゃなかったりして?)
mittyorz: @AknEp 別にそこまでは…w
mittyorz: @yshibata @AknEp いや、Linuxです。Windowsだとたぶん色々あると思う…。まぁWindowsだと「DF」というマイナーなソフト使ってますが。
yshibata: @mittyorz @AknEp diff -qrではダメかな? diffがどの過程でメモリを食うかによるんだけど...
mittyorz: @yshibata @AknEp 「Output only whether files differ.」これですか、良さそうですね。でかいテキストファイルつくって試してみよう…
mittyorz: diffのman、「binary」って単語で目grepしてたから気づかなかった…>-q
AknEp: @mittyorz @yshibata なるほどーww
yshibata: @mittyorz @AknEp -qつけたときに(いわゆる短絡評価的な)簡略化する処理を含めて入っていれば問題なく動きそう.ただ,-qつけても全部比較して,出力だけ変える場合にはアウトな気がする(以前と同様にして,mallocに失敗して落ちるか何かだと思う).
mittyorz: 1GBのランダムテキスト生成中…
mittyorz: @yshibata @AknEp だめっぽいです。 http://twitpic.com/43mmga
AknEp: @mittyorz @yshibata やっぱハッシュとるしかw
mittyorz: @AknEp きっと @yshibata さんがステキなツールを作ってくれる…!
yshibata: @mittyorz 確かに @AknEp さんが言うように,ハッシュ取って比較が早そうw
mittyorz: @yshibata @AknEp ふむー。適当なスクリプト用意するしかないですかね-。まぁ、たまにしか需要が無いので、何かのコマンドで無いかなーと投げたんですがw
mittyorz: @yshibata @AknEp ファイル同士だと「cmp」ってコマンドがあるんですが、これはディレクトリとかに使えないみたい。ということは再帰的にcmpするスクリプト書けばいいのかなぁ
yshibata: @mittyorz @AknEp 再帰的に指定したディレクトリ以下のファイルのパスとハッシュを出力するシェルスクリプトってのはどうかな? それを比較の対象元・先に行って,最後はdiffに食わせる.
yshibata: @mittyorz @AknEp あぁ,それでも良さそうだね>再帰的にcmp
mittyorz: @yshibata @AknEp ファイルのハッシュをそれぞれ取るのと、cmpで比較するのはIO量的には変わらないと思うので(あるいは違うことが分かった時点で読み取りを終えるかも知れないcmpが少ないかも)、cmpにしようかなぁと。あと、無いとは思うけどハッシュかぶったりとか。
mittyorz: @yshibata @AknEp cmpだと問題なく比較出来るみたい。メモリ食いつぶすこともなく。 http://twitpic.com/43muk7
comment:3 Changed 12 years ago by mitty
- CentOS 5.8上の、diff (GNU diffutils) 2.8.1には--diff-programというオプションがある
- $ diff --diff-program
diff: 認識できないオプション`--diff-program'です diff: 「diff --help」で、より詳細な情報を調べてみてください。
- CentOS 5.8でも、export LANG=Cで英語版のmanを見ると無いので、古い日本語訳が残っている?
- $ diff --diff-program
- OS X 10.6.8の同じバージョンのものには無い
- Ubuntu 12.04.1 LTSのdiff (GNU diffutils) 3.2にも無い
comment:4 Changed 12 years ago by mitty
- Status changed from new to assigned
- command line - Directory "diff"? - Unix and Linux
You should use rsync instead. Something like rsync -rv $old/ $new/ should do the trick: this will print the files it's going to copy over.
Run with additional -n for a dry-run before actually modifying the new directory.
- rsync (+ ssh) で簡単バックアップ
- Command Technica:はじめてrsyncを使う方が知っておきたい6つのルール (1/2) - ITmedia エンタープライズ
- そのディレクトリも含めてコピーしたい場合:「/」なし
- そのディレクトリ以下のツリーをコピーしたい場合:「/」あり
- rsync --help
-c, --checksum skip based on checksum, not mod-time & size
comment:5 Changed 12 years ago by mitty
- nul character terminationなので、ファイル名に空白等が含まれていても適切に処理されるはず
- このせいでread関数が使えない(zshでは使えるらしい)
- bash: read file line by line (lines have '\0') - not full line has read??? - The UNIX and Linux Forums
- usage: cmpdir dir1 dir2
- $ tree -aF example/
example/ ├── a/ │ ├── aa/ │ ├── differ │ ├── hoge │ └── same └── b/ ├── bb/ ├── differ ├── fuga ├── hoge └── same
- $ ./cmpdir example/a example/b
./cmpdir: start comparing 'example/a' and 'example/b' cmp: example/a/./: Is a directory cmp: example/b/./aa: No such file or directory cmp: example/a/./bb: No such file or directory cmp: EOF on example/a/./differ cmp: example/a/./fuga: No such file or directory
- $ tree -aF example/
- restriction
- 比較パスがディレクトリであろうが通常ファイルであろうが、チェックせずにcmpで比較
- 「cmp: hoge/: Is a directory」といわれてしまう
- xargsにシェル関数を渡すことが出来ない
- 違いがあったディレクトリ以下はそれ以上深く比較する必要は無いはずだが、skipしていない
- 比較パスがディレクトリであろうが通常ファイルであろうが、チェックせずにcmpで比較
comment:6 Changed 12 years ago by mitty
- $ tree -aF example/
example/ ├── a/ │ ├── aa/ │ ├── differ │ ├── hoge │ ├── piyo │ └── same └── b/ ├── bb/ ├── differ ├── fuga ├── hoge ├── piyo/ └── same
- $ ./cmpdir example/a example/b
./cmpdir: start comparing 'example/a' and 'example/b' Only in 'example/a': './aa' Only in 'example/b': './bb' example/a/./differ example/b/./differ are differ Only in 'example/b': './fuga' 'example/a' is a regular file but 'example/b' is a directory
- とりあえず用途に足る物は完成
- findの仕様で「./」が付くのが難点
- 再帰的に cmpdir を呼んでいるのでファイル数が多いとオーバーヘッドが馬鹿にならないはず
comment:7 Changed 12 years ago by mitty
- $ ./cmpdir example/a example/b
./cmpdir: start comparing 'example/a' and 'example/b' 'example/a/./piyo' is a regular file but 'example/b/./piyo' is a directory
- ./piyo の部分が抜けていたのを修正
cmp,diff,diff -qによるメモリ使用量比較