連載
» 2017年05月11日 05時00分 公開

Linux基本コマンドTips(108):【 patch 】コマンド――テキストファイルに差分を適用する(応用編)

本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、テキストファイルに差分を適用する「patch」コマンドです。

[西村めぐみ,@IT]
「Linux基本コマンドTips」のインデックス

Linux基本コマンドTips一覧

 本連載では、Linuxの基本的なコマンドについて、基本的な書式からオプション、具体的な実行例までを分かりやすく紹介していきます。今回はテキストファイルに差分を適用する「patch」コマンドです。

patchコマンドとは?

 「patch」はテキストファイルに差分を適用するコマンドです。古いファイルと差分ファイルを基に、新しいファイルを作成します。差分ファイルは「diff」コマンド(第102回105回)を使って作成します。

 差分ファイルを“パッチファイル”、差分を適用することを“パッチを当てる”というように表現することがあります。



patchコマンドの書式

patch [オプション] 元のファイル 差分ファイル

patch -p 数字 < 差分ファイル

※[ ]は省略可能な引数を示しています





patchコマンドの主なオプション

 patchコマンドのオプションを4種類に分けて紹介します。最初は差分ファイル関係の主なオプションです。

短いオプション 長いオプション 意味
-i ファイル名 --input=ファイル名 差分を指定したファイルから読み取る(デフォルトは標準入力)
-n --normal 差分をノーマルdiff(diffのデフォルト出力による差分)として解釈する
-c --context 差分をコンテキストdiff(diff -cで出力した差分)として解釈する
-u --unified 差分をunified形式のコンテキストdiff(diff -uで出力した差分)として解釈する
-F 行数 --fuzz=行数 コンテキストdiffに対し、適用する位置を探す際に無視できる行数を指定。デフォルトは2。diff -cで出力した際の行数(デフォルトは3)より大きな数を指定しないよう注意。数字が大きいと間違った場所に適用される場合が多くなる
--binary 全てのファイルをバイナリモードで読み書きする(diff -a --binaryで作成した差分を対象とする)
-e --ed 差分をedスクリプトとして解釈する
-D 名前 --ifdef=名前 差分を#ifdef "名前"〜#endif形式で適用する

 patchコマンドの差分適用時の処理に関係したオプションは次の通りです。

短いオプション 長いオプション 意味
-d ディレクトリ --directory=ディレクトリ 指定したディレクトリへ移動してから他の処理を行う
-p個数 --strip=個数 差分に記載されたファイル名から指定した個数分のパス指定を取り除く(本文参照)
-R --reverse 新旧のファイルが反転していると見なす
-N --forward 反転していると思われる差分や適用済みと思われる差分を無視する
-l --ignore-whitespace 空白の個数の違いや行末の空白の有無による違いを無視する
-E --remove-empty-files 差分を適用した結果空になったファイルを削除する
-o ファイル名 --output=ファイル名 指定した名前のファイルに出力する(デフォルトは同名のファイルで置き換える:本文参照)
-r ファイル名 --reject-file=ファイル名 適用できなかった差分(reject)を出力するファイル名。指定していない場合は「元のファイル名.rej」に出力
-Z --set-utc 差分の適用で内容が書き換わった場合、適用後のファイルの変更日時とアクセス日時をコンテキスト差分ファイルのヘッダに書かれているタイムスタンプに設定する(時刻はUTCであるものと見なす)
-T --set-time 差分の適用で内容が書き換わった場合、適用後のファイルの変更日時とアクセス日時をコンテキスト差分ファイルのヘッダに書かれているタイムスタンプに設定する(ヘッダはローカルの時刻を使っていると見なすため非推奨)
--quoting-style=スタイル ファイル名を出力するスタイルを以下から指定。デフォルトは環境変数 QUOTING_STYLEで指定可能、指定がない場合はshellとなる

 「literal」 ファイル名をそのまま出力
 「shell」 必要に応じシェル用の引用符を付けて出力
 「shell-always」 常にシェル用の引用符を付けて出力
 「c」 C言語文字列と同様な引用符を付けて出力
 「escape」 「c」同様に引用符を付けるが、最初と最後の二重引用符は省略する

 patchコマンドのバックアップに関係する主なオプションは次の通りです。

短いオプション 長いオプション 意味
-b --backup バックアップファイルを作成する(バックアップファイル名の決め方は-Vオプションで指定)
--backup-if-mismatch 適用できなかった差分があり、かつ、バックアップが指定されていなかった場合にファイルをバックアップする(POSIXに準拠していない場合のデフォルト)
--no-backup-if-mismatch 適用できなかった差分があり、かつ、バックアップが指定されていなかったらファイルをバックアップしない(POSIX準拠時のデフォルト)
-V 命名法 --version-control=命名法 バックアップファイルの名前を決定する方法を以下から指定する。デフォルトは環境変数PATCH_VERSION_CONTROLまたはVERSION_CONTROLで指定可能、指定がない場合はexistingとなる

 「existing または nil」 番号付きのバックアップがある場合はバックアップに番号を付けるが、ない場合は簡易バックアップを作る
 「numbered または t」 バックアップに番号を付ける(file.txtならばfile.txt.~1~のようになる)
 「simple または never」 簡易バックアップ(ファイル名は-B,-Y,-zのいずれかで指定、指定がない場合は環境変数SIMPLE_BACKUP_SUFFIX、いずれも指定していない場合はファイル名の末尾に.origを付ける)
-B 文字列 --prefix=文字列 簡易バックアップファイル名で、元のファイル名の前に文字列を付ける(「-B /junk/」と指定すると、「src/file.c」のバックアップは「/junk/src/file.c」となる)
-Y 文字列 --basename-prefix=文字列 簡易バックアップファイル名で、ファイル名のベース名に文字列を付ける(「-Y .del/」と指定すると、「src/file.c」のバックアップは「src/.del/file.c」となる)
-z 文字列 --suffix=文字列 簡易バックアップファイル名で、元のファイルの末尾に文字列を付ける(「-z ~」と指定すると、「src/file.c」のバックアップは「src/file.c~」となる。環境変数SIMPLE_BACKUP_SUFFIXでも指定可能)

 patchコマンドの全体的な動作に関係する主なオプションは次の通りです。

短いオプション 長いオプション 意味
--dry-run 差分を当てた場合の結果を表示する(実際にはファイルの変更を行わない)
-s --silent/--quiet エラーメッセージ以外は出力しない
--verbose 処理中の情報を出力する
-t --batch ユーザーに問い合わせずに処理を行う

・ヘッダにファイル名を含まない差分ファイルはスキップする(-fと同じ)
・ファイルのバージョンが差分中の Prereq:の行に書かれたバージョンと違っていても差分を適用し、差分が反転しているように見える場合は反転していると見なす
-f --force ユーザーに問い合わせずに処理を行う

・ヘッダにファイル名を含まない差分ファイルはスキップする(-tと同じ)
・ファイルのバージョンが差分中の Prereq:の行に書かれたバージョンと違っていても差分を適用し、差分が反転しているように見えても反転していないと見なす
・(-T/-Z指定時)ファイルの内容が書き換わらない場合もタイムスタンプを強制的に変更する
--posix POSIX標準に従う(差分を適用した結果空になったファイルを削除しない、適用できなかった差分があった場合もファイルをバックアップしないなど)


まとめてパッチを当てる

 ソースコードを管理する際などに、ディレクトリ単位で差分をとることがあります。patchコマンドでは、このような差分ファイルもまとめて適用できます。

 ここでは、「rsync」コマンド(第82回)の最新版3.1.2のソースと1つ前のバージョンの差分である「rsync-3.1.1-3.1.2.diffs.gz」を使って試してみましょう。公式サイトからダウンロードしたファイルは以下の通りです。

 まず、ファイルを展開します(画面1)。ここではtarコマンド(第40回)とgunzipコマンド(第39回)を使用しています。

画面1 画面1 ダウンロードしたファイルを展開しているところ

 3.1.2のソースは比較用です。パッチを当てる前は3.1.1と3.1.2の内容が異なっており、パッチ適用後は一致するはずです。

 diffコマンドで3.1.1のソースと3.1.2のソースを比較してみましょう(画面2)。サブディレクトリまで比較できるように-rオプションを付けて、ディレクトリ単位で比較します(第104回)。今回は確認用に違いがあるかどうかが分かればよいのでdiffコマンドの-qオプションを使用しています。量が多いため、headコマンド(第3回)で冒頭部分のみを示しました。

画面2 画面2 rsync 3.1.1と3.1.2のソースコードの違いを確認しているところ

 差分ファイル(rsync-3.1.1-3.1.2.diffs)はunified形式(第103回)になっていました(画面3)。「a/ファイル名」「b/ファイル名」のように、旧ファイルは「a」というディレクトリ名、新ファイルは「b」というディレクトリ名となっている様子が分かります。

 ここでもheadコマンドで冒頭のみ確認しています。

画面3 画面3 差分ファイルの内容を確認しているところ

 それではpatchコマンドを使って、差分を適用してみましょう。

 rsyncのソースにはサブディレクトリも含まれているので、ファイルのパスからディレクトリ名(a、b)を1つ無視するために「-p1」オプションを指定します(第107回)。

 3.1.1のソースに対してパッチを当てるので、3.1.1のディレクトリ(rsync-3.1.1)へ移動してから実行します(画面4)。

 今回の場合、途中で1つファイル名が解決できなかったようです。「File to patch:」というメッセージが表示されました。ここでは画面表示を参考に「aclocal.m4」というファイル名を入力して続行しています(画面5画面6)。

コマンド実行例

patch -p1 < パッチファイル名

(ファイルに差分を適用する)


画面4 画面4 ディレクトリを移動してpatchを実行したところ
画面5 画面5 処理中に解決できなかったファイル名を直接入力
画面6 画面6 無事patchの適用が完了したところ

 diffコマンドでパッチ適用済の3.1.1のディレクトリと3.1.2のディレクトリを比較してみましょう。

 パッチ適用後は確かに同じ内容になっています(画面7)。

画面7 画面7 パッチ適用済みのrsync 3.1.1と3.1.2のソースを比較したところ

 次回はケーススタディとして、今回のrsyncのソースを題材に、パッチを2回重ねて適用してしまった場合と、別の修正を施した後にパッチを適用する場合を紹介します。



筆者紹介

西村 めぐみ(にしむら めぐみ)

PC-9801NからのDOSユーザー(LinuxはPC-486DXから)。1992年より生産管理のパッケージソフトウェアの開発およびサポート業務を担当。のち退社し、ライターとして活動。著書に『図解でわかるLinux』『らぶらぶLinuxシリーズ』『はじめてでもわかるSQLとデータ設計』『シェルの基本テクニック』など。2011年より、地方自治体の在宅就業支援事業にてPC基礎およびMicrosoft Office関連の教材作成およびeラーニング指導を担当。


Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。