フォルダ ファイル 比較 コマンドの選び方|macOSでの実際

作業用のドライブとバックアップ用のドライブに同じ名前のフォルダがあり、中身が一致しているかを確かめたい。フォルダ ファイル 比較 コマンドを探すのは、たいていこの場面です。ところが、この「一致しているか」という問いは1つではありません。名前の並びが同じなのか、バイト列が同じなのか、コピーツールが「変更なし」と判断する状態なのか、タグや権限まで含めて同じなのか。どれを聞いているかでコマンドが変わり、同じフォルダの組でも返ってくる答えが変わります。合っていないコマンドを選ぶと、きれいな「差分なし」が返ってきたのに肝心の違いだけが報告されない、という結果になります。

ここでは、比較の種類を分けたうえで、macOSに標準で入っているコマンドが実際に何を測っているのか、Linux向けの手順をそのまま持ち込むと何が食い違うのか、そしてコマンドでは原理的に見えない差は何かを順に整理します。

比較を始める前に「同じ」の定義を分ける

先に定義を決めておくと、コマンドの選択はほぼ自動的に決まります。分け方は次の4種類です。

  • 名簿が同じ。片方にあって片方に無いパスがあるかどうかだけを見る。中身は一切読まないので最も速く、コピーが途中で止まった直後にはこれで足りる
  • 中身が同じ。バイト列が一致するかどうかを見る。全部読むので遅いが、転送中に壊れたファイルを見つけられるのはこれだけ
  • 同期ツールから見て同じ。サイズと更新日時が一致していて、コピーが実行されない状態を指す。速いかわりに、たまたま両方が一致した別内容のファイルを見逃す
  • 付帯情報まで同じ。権限、拡張属性、Finderのタグ、フラグまで含める。macOS特有の落とし穴はここに集まっていて、一般的な比較コマンドではまず扱えない

名簿だけを見る比較と、付帯情報まで見る比較は、精度の高い版と低い版という関係ではありません。別々の検査です。バックアップの検証で必要なのは2番目、コピー漏れの確認で必要なのは1番目、というように用途が違います。

diff は中身を読む。ただしmacOSのdiffはLinuxのものと同じではない

再帰的にフォルダを比較する標準の答えは diff -r です。両方のツリーをたどって、中身が違うファイルと、片側にしか無い項目の両方を報告します。フォルダの比較では出力を1行にまとめる -q を足すのが実用的です。

diff -qr /Volumes/Backup/Project ~/Project

出力は「両方にあるが中身が違うファイル」「左だけにある項目」「右だけにある項目」の3種類に分かれます。スクリプトに組み込むなら終了ステータスを見ます。差が無ければ0、差があれば1が返ります。

macOSで注意が要るのは、この diff がGNU diffutilsではないことです。macOS 26で diff --version を実行すると Apple diff (based on FreeBSD diff) と表示され、扱えるオプションはGNUの説明書より少なくなっています。ただし、よく「無い」と書かれる色付き出力は使えます。--color=when はmanページに載っていて、never always auto の3つを取り、削除行が赤、追加行が緑になります。既定の auto は出力先が画面のときだけ色を付ける決まりなので、パイプに流したときに色が消えるのは仕様どおりです。色そのものを変えたいときは DIFFCOLORS に2つの指定を渡します。

DIFFCOLORS='01;35:01;36' diff --color=always 旧.txt 新.txt

実際に足りないのは別のオプションです。1つのファイルを複数と突き合わせる --from-file--to-file、行末の空白を無視する --ignore-trailing-space(短い形の -Z)、左右表示を片側だけにする --left-column は、いずれも unrecognized option で止まります。GNU向けに書かれた手順が通らないのはこの4つのあたりで、しかも黙って結果が変わるのではなくエラーで止まるので、気づかないまま誤った報告を読む心配はありません。フォルダ比較で実際に使うオプションのほうは揃っています。

オプション 働き
-r サブフォルダまでたどる
-q 違うという事実だけを出す
-s 一致したファイルも報告する
-N 片側に無いファイルを空として扱う
-x パターン 一致した名前を除外する
-X ファイル 除外する名前を書いた一覧を渡す
--color=always パイプやページャに流しても赤と緑を残す

実務で効くのは -x です。両方のフォルダをFinderで開いたことがあると .DS_Store が生まれて差分に並ぶため、除外しておかないと本題が埋もれます。この方法の限界は、中身を全部読むところにあります。大きな動画が並ぶフォルダでは両側の全バイトを読むことになりますし、どちらが新しいのかは教えてくれません。

rsync の空実行は「どちらに何が起きるか」を答える

diff は差があることまでしか言いません。片方をもう片方に反映したら何が起きるのかは、空実行で見ます。

rsync -rin --checksum --delete ~/Project/ /Volumes/Backup/Project/

-n を付けている間は一切書き込みません。-i は1行ずつ何が起きるかを記号で示し、新しく作られるファイルは >f+++++++、中身が違うファイルは >fc......、コピー元に無いために消えるファイルは deleting の行で出ます。--checksum を付けると、サイズと日時による判定ではなく中身で比べます。前節の定義でいう2番目と3番目の違いがここに現れます。末尾のスラッシュの有無で意味が変わる点にも注意が要ります。付けるとフォルダの中身どうしの比較、付けないと「そのフォルダを行き先の中に置く」という指定になります。

ここにもmacOS特有の事情があります。macOS 26で rsync --version を実行すると openrsync と表示され、rsync version 2.6.9 compatible と続きます。よく使うオプションは揃っていますが、GNU版で知られているものが全部あるわけではありません。拡張属性を運ぶ -X とアクセス制御リストの -A は、この版では invalid option を返します。Finderのタグをコピー先へ運ぶ目的でこれらを指定していた手順は、動いている前提で放置せず確認したほうがよい部分です。拡張属性ごと複製したいだけなら、標準で入っている ditto が同じ役割を担います。

両方を並べられないときは、ハッシュの一覧で突き合わせる

同時にマウントできない相手と比べるときは、ファイルではなく一覧を突き合わせます。両側でファイルごとのハッシュを出し、その2つのテキストを比較します。

cd side_a && find . -type f -exec shasum {} + | sort > /tmp/A.txt
cd side_b && find . -type f -exec shasum {} + | sort > /tmp/B.txt
comm -3 /tmp/A.txt /tmp/B.txt

comm -3 は両方に共通する行を落として、残りだけを出します。左側の固有行は行頭から、右側の固有行はタブ1つ分下げて表示されます。ハッシュもパスも一致したファイルは出力から消えるので、残ったものがそのまま差になります。

つまずきやすいのは並べ替えのキーです。パス順に整えたくなって sort -k2 と書くと、この方法は壊れます。comm は2つの入力が行全体で並べ替えられている前提で突き合わせを進めるため、2番目のフィールドだけで並べると足並みが崩れ、一致しているはずのファイルまで差として出てきます。キーを指定しない素の sort が正解です。どうしてもパスで並べたいなら、突き合わせる道具を comm ではなく join に替えます。

macOSの shasum は既定でSHA-1を使います。転送の失敗や破損を見つける用途には十分です。改ざんへの耐性まで求めるなら shasum -a 256 に切り替えます。

mtree なら「その時点の状態」を記録して、あとから照合できる

macOSには /usr/sbin/mtree も入っています。ハッシュの一覧でやろうとしていることを、そのための道具として用意したものです。まずフォルダの状態を書き出した仕様ファイルを作り、別のフォルダをその仕様と照合します。

mtree -c -p side_a -k sha256digest,size,type > /tmp/spec.txt
mtree -f /tmp/spec.txt -p side_b

報告は差分の書式ではなく、3つの語で返ります。ダイジェストが一致しないファイルは changed として、期待値と実測値の両方を添えて出ます。仕様に無いのに存在するファイルは extra、仕様にあるのに見つからないファイルは missing です。この語の並びは、冒頭で分けた「名簿が同じか」「中身が同じか」にそのまま対応するので、出力を加工しなくても読めます。

-k に何を並べるかで、記録する項目が決まります。ここが単純なハッシュ一覧との差です。modeuidgidflags を加えると権限と所有者まで仕様に入るため、中身は正しく戻っているのに所有者が違う、という状態を見つけられます。逆に項目を減らせば処理は速くなり、仕様ファイルも小さくなります。

仕様ファイルはただのテキストです。バックアップと一緒に保管したり、別のマシンへ持っていったりできます。数か月後に「仕様を書いた時点と同じ状態か」を確かめる作業が、そのファイルと対象のフォルダだけで完結します。

コマンドでは原理的に見えない差が3種類ある

ここまでのどのコマンドでも報告されない差があります。しかも2つはmacOSの保存の仕組みに由来するため、Linux向けの記事には書かれていません。

1つ目は拡張属性とFinderのタグです。中身が同じ2つのファイルの片方にだけFinderのタグを付けて diff を実行すると、終了ステータスは0になります。データ本体を比べて差が無いのだから正しい動作ですが、Finderで色の違う2つのファイルを見ている人の感覚とは合いません。属性の有無は ls -l@ で権限欄に付く @ の記号として現れ、中身は xattr -l で読めます。

2つ目は名前の扱いです。既定の設定でフォーマットされたAPFSは大文字と小文字を区別しません。Abc.txt として作ったファイルは abc.txt でも開けます。さらに濁点や半濁点の分解形と結合形も同じ名前として扱われます。Macで書き出した一覧とLinuxのサーバで書き出した一覧を並べると、テキスト上は違って見えるのに同じファイルを指している行や、見た目は同じなのにMac側では両方を置けない行が混ざります。

3つ目は日時と権限です。diff -qr はどちらにも触れず、素のハッシュ一覧も同じです。中身は正しく復元できたのに所有者が違っていて動かない、という状態は、どちらの検査も通過します。この3つのうち標準の道具で答えが出せるのはここだけで、前節の mtreemodeuid を記録させれば拾えます。

画面で見比べる道具は、比較で終わるか反映まで行くかで分かれる

コマンドの出力は一覧です。どちらを残すかを決める作業は、画面で並べて見たほうが速くなります。macOSで動くフォルダ比較の道具を、各社の公式ページに出ている条件で並べます。

道具 価格 条件
FileMerge Xcodeに同梱 opendiff でターミナルからも起動できる
Kaleidoscope 月額8米ドル(1ユーザー・3台) 無料お試し7日間、macOS Sequoia 15以降
Beyond Compare 5 Standard 35米ドル / Pro 70米ドル Windows・macOS・Linux対応
Araxis Merge Standard 39,000円 / Professional 74,000円 永久ライセンス、30日間の無料お試し
ForkLift 4 19.95米ドル 2画面のファイル管理アプリに同期表示が付く

Araxis Merge については、購入ページに条件が明記されています。

1 つの永久ライセンスで、Windows と macOS のどちらでもご利用になれます。ご購入後 1 年間は、アップグレードが無料でご利用いただけます。 出典: araxis.com

39,000円74,000円を出すかどうかの分かれ目は、機能の数ではありません。比較で終わるのか、そのまま反映まで行くのかです。差分ビューアは違いを示すところまでを担当します。ForkLiftが公式ページで説明している同期表示のように、一致・変更・新規・削除を並べて片方向または双方向に反映するものは、答えを見たあとの操作まで含めて設計されています。監査として比較するのか、コピー作業の前半として比較するのかで、必要な道具が変わります。なお、FileMergeはXcodeに同梱されているため、開発環境を入れてあるMacでは追加の費用なしで使えます。

比較する場所と実行する場所を同じ窓に置く

ここまでの作業を並べると、ターミナルで diff -qr を打ち、出てきたパスの一覧を読み、そのパスをFinderで探して中身を確かめ、また戻って rsync -n を打つ、という往復になります。遅いのはコマンドそのものではありません。一覧に出たパスを別の窓で探し直すところです。フォルダの階層が深いほど、この探し直しに時間がかかります。

フォルダとターミナルとAIが同じ窓にある形にすると、この往復が消えます。同じ窓の中で比較コマンドを実行し、出てきたパスをその場のフォルダ表示で開き、拡張属性を xattr -l で確かめてから反映まで進められます。フォルダの一覧とシェルを同じ窓に置いたときに何ができるのかはできることに機能ごとの説明があります。専用の差分ツールを買うべきなのか、ファイル管理アプリ側でまかなえるのかを比べたい場合は、道具の担当範囲を並べた他のファイル管理との比較が判断材料になります。条件と費用を含めて考えるなら料金にまとまっています。

比較は、定義を決めた時点でほぼ終わっています。残りは、その定義に合うコマンドを選び、結果を見る場所と実行する場所を近づけるだけです。

よくある質問

diffで「差分なし」と出たのに、Finderでは違って見えるのはなぜですか?

diff が比べているのはファイルの中身と名簿だけだからです。Finderのタグ、拡張属性、権限、更新日時、色ラベルは比較の対象に入りません。中身が同じでタグだけ違う2つのファイルは、終了ステータス0で「一致」と報告されます。属性を見たいときは ls -l@xattr -l を使ってください。

macOSのdiffはLinuxのdiffと同じものですか?

同じではありません。macOS 26では Apple diff (based on FreeBSD diff) と表示され、扱えるオプションはGNU diffutilsより少なくなっています。ただし色付き出力は違いではありません。--color=never --color=always --color=auto はどれも動き、DIFFCOLORS で色も変えられます。実際に無いのは --from-file --to-file --ignore-trailing-space --left-column の4つで、指定すると unrecognized option で止まります。フォルダ比較で使う -r -q -s -N -x -X は揃っているので、実務で困る場面は限られます。

何もコピーせずにフォルダの差だけを確認する方法はありますか?

rsync-n を付けると空実行になり、書き込みは一切行われません。-i を併せると1行ずつ何が起きるかが記号で表示され、--checksum を足せばサイズと日時ではなく中身で判定します。出力を読んで納得してから -n を外す、という順番で使ってください。

大きなフォルダでは diff とハッシュ一覧のどちらが速いですか?

どちらも全バイトを読むため、1回きりの比較なら大差はなく、書き方が簡単な diff -qr で足ります。差が出るのは繰り返すときです。ハッシュの一覧は保存しておいて別の機会や別のマシンの一覧と突き合わせられるので、片側あたり1回の読み取りで済みます。

記事一覧へ戻る