Opened 9 years ago

Last modified 7 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)

  • diff -r
    • 巨大なテキストファイルを喰うと死ぬ
  • cmp
    • 二つの「ファイル」を比較する
    • 再帰的比較が出来ない
  • cmp,diff,diff -qによるメモリ使用量比較

Attachments (1)

diff-cmp.png (9.3 KB) - added by mitty 9 years ago.
cmp,diff,diff -qによるメモリ使用量比較

Download all attachments as: .zip

Change History (8)

Changed 9 years ago by mitty

cmp,diff,diff -qによるメモリ使用量比較

comment:1 Changed 9 years ago by mitty

  • Description modified (diff)

comment:2 Changed 9 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 8 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を見ると無いので、古い日本語訳が残っている?
  • OS X 10.6.8の同じバージョンのものには無い
  • Ubuntu 12.04.1 LTSのdiff (GNU diffutils) 3.2にも無い

comment:4 Changed 8 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 --help
     -c, --checksum              skip based on checksum, not mod-time & size
    

comment:5 Changed 8 years ago by mitty

  • 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
      
  • restriction
    • 比較パスがディレクトリであろうが通常ファイルであろうが、チェックせずにcmpで比較
      • 「cmp: hoge/: Is a directory」といわれてしまう
      • xargsにシェル関数を渡すことが出来ない
    • 違いがあったディレクトリ以下はそれ以上深く比較する必要は無いはずだが、skipしていない
Last edited 7 years ago by mitty (previous) (diff)

comment:6 Changed 8 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 を呼んでいるのでファイル数が多いとオーバーヘッドが馬鹿にならないはず
Last edited 7 years ago by mitty (previous) (diff)

comment:7 Changed 8 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 の部分が抜けていたのを修正
Last edited 7 years ago by mitty (previous) (diff)
Note: See TracTickets for help on using tickets.