how to compare two foldersを、順番を決めてから実行する
フォルダを比べるという作業には、少なくとも3種類の別々の仕事が混ざっています。コピーが最後まで正しく終わったかを確かめる作業と、2つの作業コピーのどちらが新しいかを見極める作業と、書類の中で何が変わったかを一覧にする作業は、必要な検査も、かかる時間も違います。しかも、よく紹介されるコマンドの1つは、中身が違う2つのフォルダを「同じ」と報告することがあります。順番を決めてから手を動かすと、この分野の面倒はほとんど消えます。
比較の需要が増えたのは、置き場が分かれたから
同じ内容のフォルダが複数の場所にできる状況は、以前より確実に増えました。本体、iCloud Drive、業務用のクラウド、外付けのSSD、共有サーバー、そして別の端末。どれか1つに寄せる運用ができれば比較は不要ですが、実際には出張先で外付けに入れて持ち出す、共有前に手元で整えるといった事情が挟まります。結果として、あとから「どちらが正か」を判定する作業が発生します。
判定を誤ると、失われるのは時間ではなくファイルです。だからこそ、検査を選ぶ前に、何をもって同じと呼ぶのかを先に決める必要があります。
手順1:何をもって「同じ」とするかを決める
ターミナルを開く前に、問いを1つに絞ります。問いは3つあり、それぞれ行き先が違います。
| 知りたいこと | 見るべき対象 | おおよその費用 |
|---|---|---|
| コピーは無事に終わったか | 全ファイルの中身すべて | 両側を最後まで読む |
| どちらが新しい作業を持っているか | 名前、大きさ、更新日時 | 一覧の情報だけで済む |
| 書類の中で何が変わったか | 中身を行単位で表示 | 遅く、専用の画面が要る |
1つ目は検証の仕事です。両側を全部読む以外に、正直に答える方法はありません。所要時間は総容量に比例します。2つ目は仕分けの仕事で、ファイルを開かないため10万件規模の階層でも数秒で終わります。3つ目は編集の仕事で、一覧ではなく画面を持つ道具の領分です。
この3つを混ぜると事故になります。更新日時でバックアップを検証するのは、どの道具でも書き換えられる値を信じることです。どちらのノートPCに新しい下書きがあるかを知るために中身の要約値を計算するのは、すぐ手に入る情報のために1時間待つことです。検査が問いを決めるのではなく、問いが検査を決めます。
手順2:両側が本当にそこにあるかを確かめる
比較の道具は、読めたものについてしか報告しません。Macには、フォルダが見た目より不在になる経路がいくつかあります。
1つ目はiCloud Driveです。デスクトップと書類をiCloudに置いていると、Finder上は揃って見えるのに中身が手元に無い状態が起こります。
iCloud Driveに保存されている項目が、まだMacにダウンロードされていない場合があります。 出典: support.apple.com
この状態のフォルダに中身の検査をかけると、触れた項目のぶんだけダウンロードが始まります。数分で終わるはずの確認が長い転送に変わり、通信量に制限のある回線では途中で止まることもあります。先に意図的にダウンロードしておくか、手元に実体があるフォルダで比べてください。
2つ目はアクセス権です。読む権限が無いサブフォルダは、エラーではなく「中身が0件」として扱われることが多く、比較はそこを素通りして正常終了します。3つ目は接続が切れたネットワークボリュームで、失敗ではなく空の一覧として返ってくる道具があります。
4つ目は、比較している最中に片側が書き換わっている場合です。クラウドの同期用ソフトが動いていれば、走査の途中でファイルが増えたり消えたりします。バックアップの実行中も同じで、読み取りが遅くなるだけでなく、走査を始めた時点と終えた時点で対象が変わります。結果は嘘ではありませんが、どの瞬間についての報告なのかが分からなくなります。件数を数える工程を2回続けて実行し、同じ数字が返るかを見れば、この状態はすぐ分かります。数字が動くなら、同期用ソフトを一時停止してから本番の検査に入ってください。
4つとも、安く防げます。高い検査を始める前に、両側の件数を数えて突き合わせてください。
find /path/to/A -type f | wc -l
find /path/to/B -type f | wc -l
件数が大きく食い違うなら、構造の側に問題があるので、中身の比較にはまだ意味がありません。近い数字なら、その差自体が次に何を探すべきかの手がかりになります。
手順3:名前の照合から始める
いちばん安い検査から始めます。これだけで答えが出ることも多いためです。狙いは、片側にしか無い項目の一覧を、ファイルを1つも開かずに得ることです。
diff <(cd /path/to/A && find . -type f | sort) \
<(cd /path/to/B && find . -type f | sort)
両側を相対パスの並んだ一覧に変え、テキストとして比べています。左向きの記号が付いた行は前者にしかない項目、右向きの記号が付いた行は後者にしかない項目です。ファイルを開かないので、大きな階層でも数秒で終わります。
多くの記事が勧める diff -rq A B は、これより踏み込みます。片側にしか無い項目は Only in A: 名前、中身が違う項目は Files A/x and B/x differ という決まった形で出ますが、後者を判定するためにファイルを開いて読んでいます。小さな階層では適切で、写真のライブラリでは適切ではありません。Finderが各フォルダに書き込む表示設定のファイルを黙らせるには、-x '.DS_Store' を付けます。
名前の照合には、中身の検査では見えにくい形が現れるという利点もあります。
- 階層を1つ深く入れてコピーしてしまった場合は、全てのパスが片側だけに並びます。パスの一覧なら一目で分かりますが、中身の比較では全損に見えます
- 転送が途中で止まった場合は、欠けているパスが五十音順やアルファベット順にひと続きで並びます。削除されたのではなく止まったのだと判断できます
- 名前の付け替えだけが行われた場合は、同じ数の項目が両側に1件ずつ現れます
差分が数千行に膨らんだときは、一覧を読み込む前に、どの枝で食い違っているのかを先に絞ります。両側の直下のフォルダごとに件数を出し、数字が合わない枝だけを深く追う方法です。
cd /path/to/A && for d in */; do echo "$(find "$d" -type f | wc -l) $d"; done
同じ行を行き先側でも流し、2つの出力を並べます。全体で2万件の階層でも、実際に食い違っているのが1つか2つの枝であることは珍しくありません。そこだけを対象にすれば、以降の検査も読む量も一気に軽くなります。ここで枝ごとの数字がすべて一致していながら全体の件数が合わないなら、原因は直下の単独ファイルか、隠しファイルの側にあります。
結果は、何かする前に読んでください。片側にしか無い項目と、中身が違う項目は、原因も対処も別です。1つの一覧として扱うと、残すべき側を上書きすることになります。
手順4:中身の照合と、そこに潜む落とし穴
多くの解説が勧めるのは、同期の予行演習です。
rsync -avn --delete /path/to/A/ /path/to/B/
実際に役立ちますし、何も書き換えません。ただし、ほとんど説明されない制限があります。既定では、転送が必要かどうかの判定を、中身ではなく大きさと更新日時から行っています。マニュアルは、もう一方の指定について「通常の大きさと更新日時による簡易な確認ではなく、ファイル全体の要約値を使う」と説明しています。
結果は簡単に再現できます。同じ長さで、同じ秒のうちに書き換えられた2つのファイルは、既定の実行では一致として報告され、要約値を使う指定を足した途端に差分として現れます。長さを変えずに書き換わるもの、たとえば固定長の記録、一部のデータベースや索引のファイル、更新日時を意図的に保存している運用は、見ていない検査から合格の報告を受け取ることになります。
更新日時が弱い証拠である理由も押さえておくと、判断が早くなります。更新日時はファイルの横に保存された値にすぎず、普通の操作でいくらでも書き換わります。バックアップからの復元、属性を保持する指定を付けたコピー、書庫の展開は、どれも別の場所から来た日時を書き込みます。同期のソフトは、次回の実行を安定させるために意図して日時を揃えます。大きさと日時が一致するというのは、中身ではなく付随情報についての報告です。
検証が目的なら、費用を受け入れて要約値の指定を足します。
rsync -rn --checksum --delete /path/to/A/ /path/to/B/
もう1つ、覚えておく価値のある方法があります。予行演習では残らないもの、つまり記録が残ります。
cd /path/to/A && find . -type f -exec shasum {} + | sort > ~/a-manifest.txt
cd /path/to/B && find . -type f -exec shasum {} + | sort > ~/b-manifest.txt
diff ~/a-manifest.txt ~/b-manifest.txt
両側が要約値とパスの並んだテキストになり、比較はテキスト同士の差分になります。この一覧は保存でき、送れて、1か月後に3つ目のコピーと突き合わせることもできます。倉庫に1年置いたドライブを確認するときにも同じ形で使えます。あとから誰かに示す必要がある作業なら、流れて消える画面の出力より、保存された一覧のほうが価値があります。
手順5:結果を、残すべき側を壊さずに処理する
比較そのものは安全な作業です。危険なのはその後で、順番を守るかどうかで結果が変わります。
先に方向を言葉で決めます。この作業においてどちらが正なのかを、コマンドを打つ前に確定させます。次に、行き先側にしか無い項目をどうするかを決めます。残すのも消すのも妥当な判断で、その選択を担っているのが --delete の指定です。方向を取り違えたときに損失に変わるのは、この指定です。
事故の原因になりやすい細かい点が2つあります。rsync の送り元のパスは、末尾のスラッシュの有無で意味が変わります。付ければフォルダの中身、付けなければフォルダそのものです。1文字の違いで、統合ではなく入れ子のコピーができます。もう1つは、書き換えを伴う実行は必ず予行演習の指定を付けて1度流し、出力を読んでから同じ行を指定なしで実行することです。2つの行が1文字しか違わない状態にしておけば、確認したものと実行したものが食い違いません。
両側に作業がある場合の統合には、安全な1行は存在しません。これは同期の問題ではなく、判断の集合です。自動化が助けになるのは、人が見るべき項目まで絞り込む部分だけです。片側にしか無い項目は、要るか要らないかを決めるだけで済みます。中身が違う項目だけが、開いて確かめる対象です。後者が少なければ1件ずつ処理するのが最も速く安全で、多い場合は、統合せずに片方を日付を付けた名前で保管に回すほうが結果的に損が小さくなります。
処理が終わったら、同じ検査をもう一度かけます。省かれやすい工程ですが、書き換えを伴う実行が意図どおりに効いたかどうかは、ここでしか分かりません。差分が消えていれば作業は完了で、残っていれば方向か除外の指定を間違えています。2回目は対象が小さくなっているので、1回目より短い時間で終わります。
1回で終わらない作業になったとき
フォルダを1度比べるのは作業です。定期的に比べて、差分を開いて、コマンドを流して、項目を左右に移す往復が続くなら、それはフォルダの一覧とターミナル、そして手順を組み立てるAIとのやり取りをまたぐ回路になります。
窓と窓の間で、状態は渡りません。比較で挙がったファイルの一覧はターミナルの中の文字列で、それをフォルダの一覧上の選択に変えるには手で探し直すことになります。ここが、やり方より道具が効いてくる地点です。フォルダとターミナルとAIが同じ窓にある形なら、この持ち替えそのものが発生しません。各アプリの設計の違いは他のファイル管理との比較に並べてあり、実際の機能はできることで確認できます。作業の続きをiPhoneやiPadから引き取れるかどうかはiPhone・iPadから続きをにまとまっています。
よくある質問
rsyncの予行演習だけで、2つのフォルダが同一だと確認できますか?
それだけでは確認できません。既定では転送の要否を大きさと更新日時から判断するため、長さを変えずに書き換えられたファイルや、更新日時が保存されたファイルは一致として報告されます。確実な答えが必要なときは要約値を使う指定を足し、両側を最後まで読む時間を見込んでください。
片側にしか無いファイルを最も速く洗い出す方法は何ですか?
フォルダ同士ではなく、相対パスを並べた一覧同士を比べます。両側で find . -type f | sort の結果をファイルに落とし、その2つを比較してください。ファイルを開かないので、非常に大きな階層でも数秒で終わり、出力はパスの一覧になります。
中身があるはずのフォルダが空だと報告されるのはなぜですか?
多くはアクセス権です。読む権限が無いフォルダを、エラーではなく中身0件として扱う道具があります。切断されたネットワークボリュームや、まだダウンロードされていないiCloudの項目でも似た結果になります。先に両側の件数を数えておけば、3つとも気付けます。
フォルダの比較はFinderとターミナルのどちらでやるべきですか?
Finderにフォルダ同士を比較する機能はないため、実際の選択肢は標準のコマンドか、比較の画面を持つ市販アプリになります。コマンドは正確で再現でき、記録も残せます。差分が数百件あり、1件ずつ人の判断が要る場合は、画面を持つ道具に移る価値があります。