diff コマンドは二つのファイルの違いを抽出するためのコマンドです。次の2つの用途があります。
すなわち、人間にも機械にも大変重要なコマンドであります。
では、人が diff をとる価値が見出せるファイル形式は何か、代表的な拡張子 (と MIME タイプ) を紹介します。馴染みのあるマイクロソフト Word/Excel などについては、まだ登場しませんので、少々辛抱を。
.txt (text/plain)
… いわゆるプレーンテキスト=文書.tex
… 技術文書組版ソースファイル=文書ソース.md (text/markdown)
… プレーンテキスト(マークアップ言語への変換向け)=文書.html (text/html), .xml (text/xml)
… マークアップ言語形式=文書.svg (image/svg+xml)
… スケーラブルベクタグラフィックスマークアップ言語形式=イメージ.css (text/css)
… カスケードスタイルシート=文書スタイルソース.rtf (application/rtf)
… リッチテキスト形式=文書.js (application/javascript)
… プログラミング言語 Javascript のコード(実行目的に難読化は .min.js
)=実行プログラム.json (application/json)
… プログラミング言語 Javascript 由来のデータ形式=データ.ics (text/calendar)
… カレンダー及びスケジュール管理=データ.csv (text/csv)
… カンマ区切りテキスト=テキストデータ.py, .rb, .tcl, .pl
… 各種スクリプト言語ソース及び実行ファイル=実行プログラム.c, .cc
… プログラミング言語 C/C++ ソースファイル=プログラムソース.sh (application/x-sh), .bash, .ksh
… Unix 向けシェルスクリプトファイル=実行プログラム.bat
… Windows 用バッチファイル=実行プログラムこれらは人が書いて読めることが想定されていますが、それぞれその度合いは異なり、.svg
, .rtf
などは特に機械が生成する細かな情報の羅列ですし、決して人が読みやすいとは言えません。昨今の .html
, .css
なども機械が生成したファイルが主流であり、人による読みやすさはあまり重要視されていません。
一方、.txt
、.md
をはじめ、プログラムコードも人間によるメンテナンスの必要性から、人による読みやすさが担保されているファイル形式です。これらは別に圧縮や暗号化されているわけではないので、人が読めるかという問題と、読むのが面倒という問題と、区別がなかなか難しい話でもありますので、それぞれ一般的な用途での説明として捉えてください。
これらのファイルを編集している人にとっては特に、diff コマンドは必須のものとなっています。
端末での操作に慣れ親しんでいる使い手なら、以下のようなコマンドオペレーションで2つのファイルの差異を確認することはよくあります。
% diff -u cursive-fonts.css~ cursive-fonts.css⏎ --- cursive-fonts.css~ 2021-07-14 21:21:39.000000000 +0900 +++ cursive-fonts.css 2021-07-14 21:37:48.000000000 +0900 @@ -1,7 +1,7 @@ @import url("default-fonts.css"); -body { +body:not(:lang(ja)) { font-family: C-cursive, ja-cursive, C-serif, serif; } -html[lang='ja'] > body { +body:lang(ja) { font-family: ja-cursive, C-cursive, ja-serif, C-serif, serif; }
端末で、普通はこのような色はつきません。
行頭の「-+」記号で「旧新」の行を表しています。新旧というより、コマンドライン引数で渡した順番が「旧新」になっているので、そのような結果となっています。
この順番はのちの patch コマンドでも習慣になっていますので覚えておきましょう。加えて、diff の -u オプションはどのファイルとの差異なのかが付記されるので、同じく重要になってきます。
さて、この diff コマンドでは、人がファイル全体を眺めて確認するという用途にはあまり向いていません。
実は diff コマンドにも全体を見るためのオプションが用意されています。先の例なら、以下のように実行します。
% diff -y -W 128 cursive-fonts.css~ cursive-fonts.css⏎ @import url("default-fonts.css"); @import url("default-fonts.css"); body { | body:not(:lang(ja)) { font-family: C-cursive, ja-cursive, C-serif, serif; font-family: C-cursive, ja-cursive, C-serif, serif; } } html[lang='ja'] > body { | body:lang(ja) { font-family: ja-cursive, C-cursive, ja-serif, C-serif, seri font-family: ja-cursive, C-cursive, ja-serif, C-serif, seri } }
中央の「|」記号で異なる行が表されています。人によってはこれで十分でしょうけど、お世辞にも視覚的に分かりやすいとは言えません。
人が視覚的に2つのファイルの違いを全体的にみて確認します。どんな手段があるでしょうか?
実のところ、ファイルの違いを視覚化するアプリケーションは他にもたくさんあります。モノによっては画像の差異も視覚化してくれるものもあるようです。
ここでは 3. の Windows, Linux, macOS で動作する Meld オープンソースアプリケーションの実行例を紹介します。
フォルダごとファイル集合の違いが見れたりと、たいへん便利です。もっとも diff コマンドの -r オプションでフォルダごとの差異は得られますし、そちらが本家です。
GUI 向けにおける大きな違いは「行の中の文字列の差異」までもが配色で分かりやすくなっていることでしょう。
4. のウェブサービスは手元のファイルの差異をみるには情報漏洩の懸念があるなど、まったくお勧めしません。しかし、弊社謹製 v-diff であれば Javascript のみで実現されていているので安心です。
diff コマンドの出力ファイルを使った、極めて重要な活用例として patch コマンドが一番にあげられます。以下の端末での操作例で、diff と patch の新旧ファイルの自動生成が説明できます。
%
に続く文字列がオペレータが打ち込んだコマンド行です。
% diff -u cursive-fonts.css~ cursive-fonts.css > cursive-fonts.css.patch⏎ % patch --dry-run < cursive-fonts.css.patch⏎ patching file cursive-fonts.css Reversed (or previously applied) patch detected! Assume -R? [n] ^C % patch --dry-run -R < cursive-fonts.css.patch⏎ patching file cursive-fonts.css
端末での操作に不慣れな方に分かりやすく説明します。ここでは3つの操作をしており、順を追って説明します。
diff -u cursive-fonts.css~ cursive-fonts.css > cursive-fonts.css.patch
cursive-fonts.css.patch
に保存しています。これが「パッチファイル」と呼ばれるものです。このパッチファイルと新旧ファイルのどちらかがあれば、旧新ファイルが自動生成できるというわけです。--dry-run
オプションつきで、実際のファイル書き込みはしない「お試しモード」で動かしてみます。
patch --dry-run < cursive-fonts.css.patch
cursive-fonts.css
ファイルが旧ファイルなら新ファイルが自動生成されて、元のファイルは cursive-fonts.css.orig
に変更されます。patch --dry-run -R < cursive-fonts.css.patch
cursive-fonts.css.orig
に変更されます。
patch コマンドに --dry-run
オプションを指定しなければ実際に生成しますので、別のフォルダにコピーしたもので試してみるとよいでしょう。
さて、Windows 用にマイクロソフト謹製の「WinDiff」がありましたが、あくまで開発者向けに過ぎず、多くの方は「WinMerge」を使っているようです。
一方、macOS 用には開発ツール Xcode に「FileMerge」が(/Applications/Xcode.app/Contents/Applications/FileMerge.app
)付属しています。Linux など Unix 用には先の Meld です。
先のパッチ当ての作業が複雑になってくるとグラフィカルに人の目で確認して行いたいという需要もあるものですから、この手のアプリケーションは patch コマンドの機能も兼ねていることが多いです。ゆえに「Merge」という命名で、さまざまなパッチを統合して新しいファイルを生成するツールとなっているわけです。
diff コマンドはコンピュータ科学にたいへん重要な役割を果たしています。
ソフトウェア開発のウェブプラットフォームである GitHub の中核技術である分散バージョンコントロールシステム git も自前の diff, patch 互換機能を備えてますし、フリー百科事典の WikiPedia の編集における差分においてもマークダウン文書の diff から得られています。
時代を遡れば、patch の作者はスクリプト言語 Perl のラリー・ウォール氏ですし、diff の作者は Unix 創始者の一人であるダグラス・マキルロイです。1970 年代初頭から使われている技術が半世紀以上に渡って使われ続けていることは驚くべきことです。
論文などを執筆する研究者や技術者は、数式を含む \(\TeX\) 文書の更新履歴を、先のグラフィカルな diff などで誤りがないか慎重に確認します。
コードを書くブログラマは、プログラムは「 」(半角スペース)が「 」(全角スペース)になっていただけで正しくないわけですから、問題があれば動いていた時点のコードと diff などを使って慎重に誤りを探します。
このように、diff コマンドや、それを視覚化する GUI 版の活用は、確認すべきところを最小限にし誤りを人間が見つけやすくするためだけでなく、文書やプログラムコードの更新やバージョン管理にも役立っているのです。
本稿ではテキストファイルの差分について取り扱いましたが、バイナリファイルの差分についても古くから開発されており、xdelta や VCDIFF などがあげられます。こちらは人の目に直に触れる対象ではないので、さらに縁の下の力持ちと言えます。
text/plain
などの MIME タイプを管理する IANA (インターネット番号割当機関) による一次情報です。