1. 概要

このチュートリアルでは、diffコマンドを使用して、Linuxでのファイル比較の実践的な理解を深めます。

2. GNU diffUtilsパッケージ

diffコマンドは、 cmp sdiff diff3 などの他の比較ツールとともに、GNUdiffUtilsパッケージにバンドルされています。 そのため、ほとんどのLinuxディストリビューションには、diffUtilsパッケージのコピーがプリインストールされています。

したがって、diff に必要なバイナリファイルがすでにある場合は、インストールをスキップできます。 ただし、パッケージが見つからない場合、またはパッケージの別のバージョンが必要な場合は、自分でインストールする必要がある場合があります。

まず、システムでdiffバイナリファイルを確認します。

$ which diff
diff not found

diffUtils パッケージがインストールされていないようですので、インストールする必要があります。

まず、 curl コマンドを使用して、GNUFTPサーバーからパッケージのtarアーカイブを取得しましょう。

$ curl --silent --output diffutils-3.7.tar.xz ftp://ftp.gnu.org/gnu/diffutils/diffutils-3.7.tar.xz

次に、パッケージを抽出して、 / usr /binディレクトリ内にバイナリをインストールしましょう。

$ tar --extract --file diffutils-3.7.tar.xz
$ cd diffutils-3.7
$ ./configure --prefix=/usr
$ make install

そして、私たちは行く準備ができています。

3. diffの基本

これで、システムでdiffバイナリを使用できるようになりました。 その基本的な概念のいくつかを学びましょう。

3.1. 使用法

diff コマンドを使用するには、2種類の情報、つまり、比較するオプションとファイルを提供する必要があります。

diff [OPTION]... FILES

他のUnixコマンドと同様に、 diffコマンドでオプションを使用すると、デフォルト以外の動作を取得できます。 当然のことながら、利用可能なさまざまなオプションの調査を開始する前に、そのデフォルトの動作を理解する必要があります。

3.2. バイナリファイルの比較

まず、 diff を使用して、それ自体と比較してみましょう。

$ /usr/bin/diff /usr/bin/diff /usr/bin/diff
$ echo $?
0

コマンドの実行が終了コード0で正常に終了したことがわかります。これは、2つのファイルが等しいであることを示しています。

それでは、これを使用して、2つの異なるバイナリファイル / bin /mv/bin /cpを比較してみましょう。

$ /usr/bin/diff /bin/mv /bin/cp
Binary files /bin/mv and /bin/cp differ
$ echo $?
2

この場合、コマンドは2つのファイルが異なることを示唆しましたが、ゼロ以外の戻りコードで早期終了しました。 diff はバイナリの完全な比較を行わないため、これは実際には誤った警告です。

実際、 diffは、2つのバイナリが同一であるかどうかを確認するために最低限のことを行います。 これをよりよく理解するために、2つのファイルが異なる場合にのみ出力する –brief -q )オプションを使用して、この動作を模倣できます。

$ diff --brief /bin/mv /bin/cp
Files /bin/mv and /bin/cp differ
$ echo $?
1

3.3. テキストファイルの比較

バイナリファイル比較の場合とは異なり、 diff を使用すると、テキストデータの比較にはるかに多くの洞察を得ることができます。

学生向けのUnixトレーニングセッションを実施しているとしましょう。このセッションでは、「 Hello、World!」プログラムを紹介します。

$ cat script_v0.sh
#!/bin/sh
/bin/echo "Hello, World!"

現在、学習課題として、学生は同じ機能を模倣するために別のUnixコマンドを使用する必要があります。 さらに、私たちの仕事は彼らのコード提出をレビューすることです。

それでは、先に進んで、 / bin /echoコマンドの使用がshell-builtin echoコマンドに置き換えられた提出物の1つを見てみましょう。

$ cat script_v1.sh
#!/bin/sh
echo "Hello, World!"

2つのコードファイルの行ごとの比較が必要な場合は、diffが最適です。 それでは、これを使用して2つのスクリプトscript_v0.shscript_v1.shを比較してみましょう。

$ diff script_v0.sh script_v1.sh
2c2
< /bin/echo "Hello, World!"
---
> echo "Hello, World!"

私たちはそれを見ることができます diffは、最初のファイルを2番目のファイルとまったく同じになるように変更するための明確な手順のリストを提供してくれました。 よく見ると、 2c2 命令は、両方のファイルの2行目が異なることを示しています。

次に、空の行で始まり、shell-builtin printfコマンドを使用するもう1つのコード送信を見てみましょう。

$ cat script_v2.sh

#!/bin/sh
printf "Hello, \n"
printf "World!\n"

最後に、このスクリプトをscript_v0.shと比較して確認しましょう。

$ diff script_v0.sh script_v2.sh
0a1
>
2c3,4
< /bin/echo "Hello, World!"
---
> printf "Hello, \n"
> printf "World!\n"

ここでも、diffは2つのスクリプトを異なるものとして識別しました。 しかし今回は、出力に2つの命令が表示されます。

0a1 命令の後に>が続くことは、最初のスクリプトの先頭に空の行を追加すると、2番目のスクリプトの最初の行を取得することを示しています。 一方、 2c3,4 命令は、最初のスクリプトの2行目を、2番目のファイルの行のグループ(3〜4)で変更する必要があることを示しています。

前と同じように、最初と2番目のスクリプトのコンテンツにはプレフィックス記号「 < ” と “ >> “、 それぞれ。 さらに、3つのトリプルダッシュは、各ファイルからコンテンツを分離することにより、読みやすさを向上させます。

4. デフォルト以外の動作

diff コマンドによって示されるデフォルトの動作を正しく理解できたので、次はそのさまざまなオプションを検討します。

4.1. 大文字と小文字の区別を無視する

招待された学生のリストを、トレーニングセッションに参加した実際の学生のリストと比較する必要があるとします。

まず、トレーニングに招待された学生のアルファベット順のリストを提供するために、マーケティングチームの支援が必要です。

$ cat all_invitations.txt
BILLY
ROHAN
TOM

ここで、ロジスティクス管理チームが、出席.txtファイルで実際にトレーニングに参加した学生名のアルファベット順のリストを送信したと仮定します。

$ cat attendance.txt
BILLY
Kiran
tom

attendance.txt には大文字と小文字が混在しているのに対し、all_inviations.txtファイルにはすべて大文字が含まれていることに注意してください。 このようなシナリオでは、 –ignore-caseオプションを使用することをお勧めします。

$ diff --ignore-case all_invitations.txt attendance.txt
2c2
< Rohan
---
> kiran

したがって、ローハンが招待されたことがわかりますが、彼はトレーニングに参加しませんでした。 それどころか、キランは招待されなかったが、セッションに参加した。

4.2. スペースと空白行

さて、何人かの学生はセッション中に集中していませんでした。 その結果、彼らは友人からコードをコピーし、スペースと空白行を追加して、彼らをユニークに見せました。

ここで、盗用を捕まえる場合は、diffがコピーされたソリューションを同一として処理できることを確認する必要があります。

まず、script_v1.shからコードをコピーしたstudent-9によって送信されたスクリプトを見てみましょう。 さらに、 echo コマンドの後に空白行と8つのスペースを追加してスクリプトを変更し、スクリプトをscript_v1.shとは異なって見えるようにしました。

$ cat -te script_v9.sh
#!/bin/sh$
$
echo        "Hello, World!"$

diff の通常の動作では、2つのファイルが同一ではないことがわかります。

$ diff script_v1.sh script_v9.sh
2c2,3
< echo "Hello, World!"
---
>
> echo        "Hello World"

したがって、このような盗用をキャッチするには、 –ignore-blank-lines(-B)および–ignore-space-change(-b)オプションを使用する必要があります

$ diff -B -b -s script_v1.sh script_v9.sh
Files script_v1.sh and script_v9.sh are identical

また、 –report-identical-files -s )オプションを使用すると、両方のファイルの内容が同じであることが明示的に明確になりました。

さらに、場合によってはより厳密なアプローチが必要な場合は、 –ignore-all-space(-w)オプションを使用してすべてのスペースを無視することもできます

4.3. 正規表現

学生のグループが使用するもう1つの盗用戦略は、スクリプトの盗用コピーでのコメントの使用です。

script_v1.shからコピーされたscript_v8.shのコードをプレビューしてみましょう。

$ cat script_v8.sh
#!/bin/sh
#
# Hello World Program
#
echo "Hello World"

繰り返しになりますが、 diff コマンドのデフォルトの動作を使用して、この盗用を捕らえることができない場合があります。

$ diff script_v1.sh script_v8.sh
1a2,4
> #
> # Hello World Program
> #

ここで、で始まるコメントを無視するために、正規表現値^#で–ignore-matching-linesオプションを使用できます。

$ diff -s --ignore-matching-lines="^#" script_v1.sh script_v8.sh
Files script_v1.sh and script_v8.sh are identical

5. 複数のファイルの比較

これまで、 diff を使用して、一度に2つのファイルを正確に比較してきました。 これを使用して複数のファイルを比較する方法を学びましょう。

5.1. –from-fileおよび–to-file

デフォルトでは、diffは正確に2つのファイルオペランドを想定しています。 また、常に2番目のファイル名に対応するファイルを、最初のファイル名で識別されるファイルと比較します。

ただし、複数のファイルを一度に比較するという要件がある場合は、 –from-fileまたは–to-fileオプションのいずれかを使用できます。

$ diff [--from-file | --to-file] named_file list_of_files

そのため、 named_file は–( stdin )以外のファイル名です。 さらに、 –from-file オプションを使用すると、diffnamed_fileを残りのファイルのリストと比較しますが、 –to- file オプション、 diff は、ファイルのリストをnamed_fileと比較します。

次に、 –from-file オプションを使用して、script-v0.shscript-v1.shscript-v2の両方と比較してみましょう。 sh

$ diff --side-by-side --from-file script_v0.sh \
script_v1.sh script_v2.sh
#!/bin/sh                                                       #!/bin/sh
/bin/echo "Hello, World!"                                     | echo "Hello World"
                                                              >
#!/bin/sh                                                       #!/bin/sh
/bin/echo "Hello, World!"                                     |	printf "Hello, \n"
                                                              >	printf "World!\n"

読みやすさを向上させるために –サイドバイサイド(-y)出力フォーマットオプションも使用しました。 したがって、左側には script_v0.sh ファイルが表示され、右側にはscript_v1.shおよびscript_v2.shファイルが表示されます。 さらに、いくつかの記号が異なる行の接頭辞として使用されます。

  • | –パイプ記号は、行のテキストの部分的な変更を示します
  • > –直角の括弧は、線が追加されたことを示します

次に、-to-fileオプションを使用して逆比較を行います。

$ diff --side-by-side --to-file script_v0.sh \
script_v1.sh script_v2.sh
#!/bin/sh                                                       #!/bin/sh
echo "Hello World"                                            |	/bin/echo "Hello, World!"
                                                              <
#!/bin/sh                                                       #!/bin/sh
printf "Hello, \n"                                            |	/bin/echo "Hello, World!"
printf "World!\n"                                             <

出力の側面が変わっていることがわかります。 左側にはscript_v1.shファイルとscript_v2.shファイルが表示されますが、右側にはscript_v0.shが出力されます。 前に見たように、プレフィックス記号は変更を示しますが、今回は、行が欠落していることを示すために左角の括弧<があります。

5.2. ディレクトリ内のファイルの比較

ロジスティクス部門のアナリストが履歴データの分析に私たちの助けを必要としているとしましょう。 この目的のために、カレンダーのようなディレクトリ構造に編成された出席レポートを含む生データのコピーが提供されます。

attendance_calendar
├── 2019
│   ├── logistics_incharge.txt
│   ├── reports
│   │   └── January
│   │        ├── 01.txt
│   │        └── 02.txt
│   └── training_incharge.txt
└── 2020
    ├── marketing_incharge.txt
    ├── logistics_incharge.txt
    ├── reports
    │   └── January
    │        ├── 01.txt
    │        └── 02.txt
    └── training_incharge.txt

読みやすくするために、1月から数日だけが表示されています。 ただし、出席データは2019年と2020年からのすべての関連する日に利用可能であると想定できます。

ここで、Unixではディレクトリもファイルとして扱われることを念頭に置いて、 diff のバニラ動作を使用して、2019年と2020年のデータを比較してみましょう。

attendance_calendar$ diff --side-by-side 2019/ 2020/
... 2019/logistics_incharge.txt 2020/logistics_incharge.txt
Mrs. Hudson						      |	Mr. Watson
Only in 2020/: marketing_incharge.txt
Common subdirectories: 2019/reports and 2020/reports
... 2019/training_incharge.txt 2020/training_incharge.txt
Mr. Thomson						      |	Mr. Richard

diffがアルファベット順に比較するためにファイルを選択したことがわかりますが、指定されたディレクトリの直下にあるファイルのみです。 また、ディレクトリ構造の第1レベルの比較も行いました。

5.3. 再帰的な比較

デフォルトでは、diffはサブディレクトリの下にあるファイルに対して再帰比較を実行しません。 ただし、–recursive(-r)オプションを使用して有効にすることができます。

2019年と2020年の第1四半期の毎月1日の出席を比較する必要があるとしましょう。 再帰的な比較は機能するはずですが、ファイルのセットを除外する必要があります。

さて、私たちにとって良いニュースは、 diff が、そのような使用に対応するために、 –exclude = PATTERN–exclude-from =PATTERN_FILEの2つのオプションを提供することです。場合。 それでは、比較から除外する必要のあるファイルのセットについて考えてみましょう。

  • 01.txt以外のすべてのファイルを除外する必要があります
  • 3月以降の月のすべてのファイルを除外する必要があります

それでは、 excluded_patterns.txt というファイルを作成し、すべてのパターンを小文字のままにしてみましょう。

$ cat excluded_patterns.txt
0[2-9].txt
[1-3][0-9].txt
april
may
june
july
august
september
october
november
december

後で、 –exclude-fromオプションと–ignore-file-name-case オプションを組み合わせて使用して、2つのディレクトリの月名が大文字と小文字だけで異なる場合を適切に処理できます。 。

最後に、物事をまとめて、再帰的な比較を実際に見てみましょう。

$ diff \
--side-by-side \
--ignore-file-name-case \
--exclude-from=excluded_patterns.txt \
--recursive 2019/reports 2020/reports
... 2019/reports/February/01.txt 2020/reports/February/01.txt
Invitations Sent: 800					      |	Invitations Sent: 1200
Actually Attended: 275 					      |	Actually Attended: 575
... 2019/reports/January/01.txt 2020/reports/January/01.txt
Invitations Sent: 500					      |	Invitations Sent: 1000
Actually Attended: 150					      |	Actually Attended: 300
Only in 2019/reports/March: 01.txt

2020年3月の01.txtという名前のファイルがないため、3月の詳細な比較レポートがありません。

5.4. 不在のファイル

ディレクトリを操作する場合、 diff は通常、両方のディレクトリの下で同様のパスを介して到達可能なファイルのみを比較します。

2019年と2020年の第1四半期の1日目の比較レポートを生成するために使用したのと同じオプションを使用して、diffを呼び出しましょう。 ただし、今回は、 –starting-fileオプションを使用して、キーワード March “に一致するファイルパスが見つかった場合にのみ比較を開始します。

$ diff \
--side-by-side \
--starting-file=March \
--ignore-file-name-case \
--exclude-from=excluded_patterns.txt \
--recursive \
--from-file 2019/reports 2020/reports
Only in 2019/reports/March: 01.txt

diff が、ファイル01.txtが2020ディレクトリの下に到達できないと文句を言っていることがわかります。 ただし、そのようなファイルの比較に関する洞察はこれ以上得られません。

01.txt は2019ディレクトリの下にのみ存在するため、比較を確認するためのより良い方法は、存在しないファイルを空のファイルとして扱うことです。 興味深いことに、 diff には、この計画を実行するための2つのオプションがあります。

  • –new-file -N )は、いずれかのディレクトリの下にある欠落しているファイルを空の新しいファイルとして扱います
  • –unidirection-new-file は、最初のディレクトリに存在しないファイルのみを空のファイルとして扱います

それでは、最初に –new-file オプションを使用して、期待どおりに機能するかどうかを確認しましょう。

$ diff \
--side-by-side \
--starting-file=March \
--ignore-file-name-case \
--exclude-from=excluded_patterns.txt \
--new-file \
--recursive \
--from-file 2019/reports 2020/reports
... --from-file 2019/reports 2019/reports/March/01.txt 2020/reports/March/01.txt
Invitations Sent: 750					      <
Actually Attended: 350					      <

はい、そうです! それは期待どおりに機能し、より多くの洞察を与えてくれました。

ここで、制限された –unidirection-new-fileオプションの効果も見てみましょう。

$ diff \
--side-by-side \
--starting-file=March \
--ignore-file-name-case \
--exclude-from=excluded_patterns.txt \
--unidirectional-new-file \
--recursive \
--from-file 2019/reports 2020/reports
Only in 2019/reports/March: 01.txt

ああ! –new-file の代わりに–uni direction-new-file を使用して、正方形に戻ります。 ファイルは最初のディレクトリに存在しないため、これは予想される動作です。

最後に、 –to-fileおよび–unidirection-new-file オプションを使用して、逆比較レポートを生成しましょう。

$ diff \
--side-by-side \
--starting-file=March \
--ignore-file-name-case \
--exclude-from=excluded_patterns.txt \
--unidirectional-new-file \
--recursive \
--to-file 2019/reports 2020/reports
... --to-file 2019/reports 2020/reports/March/01.txt 2019/reports/March/01.txt
							      >	Invitations Sent: 750
							      >	Actually Attended: 350

比較で存在しないファイルの順序が逆になっているため、 –unidirection-new-fileオプションの効果がわかります。

6. パッチ適用

パッチ適用は、一連の差分のような変更を適用することにより、データを変更するのに役立つメカニズムです。

提供されたデータのコピーを使用していくつかの分析レポートを作成する際に、いくつかの変更を加えました。 さらに、元のデータにこれらの変更を加えるようにロジスティクスチームに依頼することも適切であると考えています。 diffがパッチ適用にどのように役立つかを見てみましょう。

6.1. edスクリプト

まず、作業ファイル01.txt.modifiedに加えた変更を見てみましょう。このファイルは元々2020/ reports / January /01.txtファイルから複製されたものです。

$ diff 01.txt 01.txt.modified
2a3
> Empty Seats: 700

トレーニング中にその日に空いた席を示す新しい行を追加したことがわかります。

ここで、データの元のコピーを保持しているチームがこれらの変更を吸収するために、次の2つのことを実行できます。

  • 完全なデータのコピーを送信し、完全な代替として使用するように依頼します
  • 行った一連の変更のみを送信し、変更されたデータにパッチを適用するようにリクエストします

2番目の選択肢は、最小限のデータを送信し、それでも作業を完了できるため、より焦点が絞られています。

さらに、 diff は、パッチ適用プロセスの自動化に役立つ編集(ed)スクリプトの形式で出力を生成できます。 このためには、 –ed(-e)オプションを使用する必要があります。

次に、01.txtファイルに加えた変更のedスクリプトを生成しましょう。

$ diff --ed 01.txt.modified 01.txt > 01.txt.ed
$ cat 01.txt.ed
2a
Empty Seats: 700
.

したがって、チームが ed スクリプトを受け取ったら、最初に01.txt.origというバックアップファイルを作成する必要があります。 次に、 01.txt.ed スクリプトを使用して、01.txtファイルを更新できます。

$ (cat 01.txt.ed && echo w) | ed - 01.txt

ここでは、01.txt.edスクリプトからstdoutに命令を書き込み、続いて write w )コマンドを記述しました。 さらに、これらの命令はパイプを介してedコマンドに渡されます。

最後に、チームは更新されたファイルを確認し、バックアップファイルを削除できます。

$ cat 01.txt
Invitations Sent: 1000
Actually Attended: 300
Empty Seats: 700
$ rm 01.txt.orig

6.2. diff -uおよびパッチ

ed スクリプトは、パッチを作成して適用する最も古い方法の1つである可能性があります。 ただし、それらはそれほどユーザーフレンドリーではなく、 ed の概念に精通すると、受信者側にオーバーヘッドが発生します。

したがって、物事をよりスムーズに実行するために、代わりに diffの–unified(-u)出力フォーマットオプションを使用してパッチファイルを作成することができます

$ diff --unified 01.txt 01.txt.modified > 01.txt.diff
$ cat 01.txt.diff
--- 01.txt	2020-04-01 14:37:00.000000000 +0530
+++ 01.txt.modified	2020-04-01 14:36:54.000000000 +0530
@@ -1,2 +1,3 @@
 Invitations Sent: 1000
 Actually Attended: 300
+Empty Seats: 700

最初は、新しいスタイルが私たちを圧倒するかもしれないので、これを少しずつ理解しましょう:

  • 2行のヘッダーは、from-fileto-fileを、最後に変更されたタイムスタンプとともに示します。
  • @@ line-range-1、line-range-2 @@ は、from-fileおよびto-fileでこの変更ブロックを見つけるのに役立ちます。それぞれ
  • –および+の使用は、最初のファイルの行の削除または追加を意味します

基本的にどのように機能するかがわかったので、 01.txt.diff ファイルをチームに送信すると、チームはパッチコマンドを使用してそれを適用できます

$ patch 01.txt 01.txt.diff
patching file 01.txt
$ cat 01.txt
Invitations Sent: 1000
Actually Attended: 300
Empty Seats: 700

このように、 diff –unifiedおよびpatch コマンドは、統合された形式でパッチワークフローを完了します。

7. 出力フォーマット

これまでに、 –side-by-side –normal (デフォルト)、 –unifiedなどのいくつかの出力形式を使用しました。 出力フォーマットをさらに制御する方法を学びましょう。

7.1. 回線タイプとグループタイプ

2つのファイルを比較している間、 diffは、2つのファイルのテキストセグメント全体を、ハンクと呼ばれる同一の行と同一でない行のシーケンスに分割します。 最終的に、diffは、2つのファイル間の非類似性の尺度として、これらのハンクに関する情報を提供します。

一般的に、単一の行でさえ、開始行番号と終了行番号が等しいサイズ1のグループでこのカテゴリに分類されます。

そのため、 diff コマンドは、2つのグループ内の変更を見つけることができます。 その結果、グループを古い、新しい、変更されていない、変更された4つのタイプに分類できます。

さらに、 diff はこれらのグループ内で反復して、行ごとの比較を行います。 したがって、個々の行に関しては、内部的に、古い、新しい、変更されていない3つのタイプに分類できます。

要するに、ラインタイプとグループタイプはLTYPEGTYPEとして知られています。

7.2. ラインフォーマットとグループフォーマット

diff によって生成される出力は、さまざまなグループタイプ内の各行の情報のコレクションです。 さらに、 –line-format –LTYPE-line-format 、および –GTYPE-group-format の3つのオプションがあり、細かく制御できます。出力フォーマットの。

ここで、LTYPEGTYPEを可能な値に置き換えると、 –old-line-format 、[ X148X] –new-line-format 、 –unchanged-line-format –old-group-format –new-group-format –unchanged-group-format 、および –changed-group-format

当然、線とグループには異なる特性があります。 したがって、diffには、ラインフォーマット(LFMT)グループフォーマット(GFMT)の2つのフォーマットカテゴリがあります。 1番目と2番目のファイルに属するライングループの境界を識別するためのさまざまなGFMTシンボルを見てみましょう。

GFMT で行番号と行コンテンツ記号の意味を視覚化した後、行コンテンツのフォーマットプロセスを明確に理解することも重要です。 それでは、GFMTLFMTの行のフォーマットの関係を見てみましょう。

さて、あります 2つのファイルからの非同一または同一の行の値を識別する3つのGFMTシンボル、つまり%<、%=、および%> 。 さらに、これらの各シンボルは LTYPE フォーマット規則によってフォーマットされ、その後、出力はstdoutにレンダリングされます。

7.3. カスタマイズ

次に、diffLFMTおよびGFMTルールをに適用して、カスタムのサイドバイサイド出力フォーマットをシミュレートします。

まず、2019年と2020年のトレーナーのデータを見てみましょう。

$ cat trainers_2019.txt
Bill
Catherine
Dave
Eve
Raymond
Susan
Zack
$ cat trainers_2020.txt
Bill
Eve
Feynman
Gabrina
Raymond
Susan
Zoe

次に、 –LTYPE-line-formatおよび–GTYPE-group-format オプションを使用して、独自のバージョンのサイドバイサイド出力フォーマットを生成しましょう。

diff \
--old-group-format='[%(f=l?L%df:L%df,L%dl)] vs [❌]:
%<' \
--new-group-format='[❌] vs [%(F=L?L%dF:L%dF,L%dL)]: %>' \
--changed-group-format='[%(f=l?L%df:L%df,L%dl)] vs [%(F=L?L%dF:L%dF,L%dL)]:
%< %>' \
--unchanged-group-format='[%(f=l?L%df:L%df,L%dl)] vs [%(F=L?L%dF:L%dF,L%dL)]:
%=' \
--old-line-format='-	%L' \
--new-line-format='				+	%L' \
--unchanged-line-format='✔️	%l				%L' \
trainers_2019.txt trainers_2020.txt

このコマンドには、LFMTGFMTのよく知られた記号がたくさん含まれていますが、よく見ると、いくつかのパターンが表示される可能性があります。

  • タブ文字は、列ビューをシミュレートするために使用されます
  • %d プレフィックスは、 f l F Lなどの行番号記号に意図された数値の意味を与えます
  • 行フォーマット記号%L および%l は、末尾の改行の有無にかかわらず、行の内容を印刷します
  • %( )。 三項演算子の機能を示します
  • 記号✔️、+、および–は、それぞれ Noop Add 、およびDelete命令にスペルアウトします
  • ❌は、対応するグループがファイルの1つに存在しないことを示します

最後に、最後のコマンドによって生成されたdiffを並べて表示します。

[L1] vs [L1]:
✔️      Bill                            Bill
[L2,L3] vs [❌]:
-       Catherine
-       Dave
[L4] vs [L2]:
✔️      Eve                             Eve
[❌] vs [L3,L4]: 
                                +       Feynman
                                +       Gabrina
[L5,L6] vs [L5,L6]:
✔️      Raymond                         Raymond
✔️      Susan                           Susan
[L7] vs [L7]:
-       Zack
                                +       Zoe

デモの観点からカスタマイズされた出力形式を作成したため、すべてのエッジケースを処理できるとは限りません。 したがって、本番コードの場合、エッジケースを処理して信頼性を向上させるか、 –side-by-sideオプションを使用する必要があります。

8. 結論

このチュートリアルでは、diffコマンドの詳細な説明に焦点を当てました。 さらに、コードレビュー、盗用チェック、ディレクトリ比較、ファイルパッチなどのいくつかのユースケースを解決するために使用しました。

そのため、より多くの調査と実践を行うことで、diffを用途の広い比較ユーティリティとして簡単に評価できます。