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

Linux基本コマンドTips(107):【 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 元のファイル 差分ファイル」で元のファイルに差分を適用します。diffコマンド(第102回105回)で作成した差分を使います。

コマンド実行例

patch 元のファイル 差分ファイル

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


 例えば、list1.csvとlist2.csv(画面1)の差分がpatchfile(画面2)という名前で保存されているとしましょう。「patch list1.csv patchfile」と実行すると、list1.csvの内容がlist2.csvと同じになります(画面3)。

画面1 画面1 list1.csv(左)とlist2.csv(右)の内容
画面2 画面2 差分ファイルの内容 diffコマンドで差分ファイル「patchfile」を作成し、catで内容を確認したところ。差分の読み方は第102回参照
画面3 画面3 元のファイルに差分ファイルを適用した結果


差分ファイルだけを指定して差分を適用する

 「diff -u」や「diff -c」で作成した差分ファイルには、元のファイル名が書かれています。このような場合、元のファイル名を指定せず、「patch < 差分ファイル」と実行するだけで差分ファイルを適用することができます。

 ソースコードなどの場合、1つのファイルに複数のファイルに関する差分が保存されていることがあります。そのような場合も「patch < 差分ファイル」で複数のファイルにまとめて差分を適用することができます。

コマンド実行例

patch <差分ファイル

(差分ファイルに書かれているファイル名に従って差分を適用する)


 画面4は、先ほどのlist1.csvとlist2.csvの差分を「diff -u」で作成したファイルです。先頭部分にファイル名が書かれています(差分の読み方は第103回参照)。

 このファイルを使用して「patch < 差分ファイル」を適用すると、list1.csvに差分が適用されます(画面5)。

画面4 画面4 diff -uで作成した差分ファイルの内容
画面5 画面5 list1.csvに差分が適用された様子


ディレクトリ名を取り除いて差分を適用する

 差分ファイルに書かれているファイル名に、ディレクトリ名がついていることがあります。差分を作成した環境と異なる環境で差分を適用したい場合、「patch < 差分ファイル」では、差分を適用させるファイルをうまく見つけられないかもしれません。

 例えば、画面6では「orgdata/csv」にファイルを保存している環境で作成した差分ファイルを、異なるディレクトリで適用させています。そのため、ファイル名を入力するよう、メッセージが表示されています。

 patchコマンドを実行しようとしている環境では、「orgdata/」はありませんが、orgdata/を取り除けば、その後の「csv/list1.csv」部分は共通です。そこで「-p」オプションを使います。

 今回の場合は「-p1」でパスを1つ分取り除くことで差分を適用することができました(画面7)。

 なお、カレントディレクトリに該当するファイル(今回の場合はlist1.csv)がある場合、「-p」オプションを指定しなくても差分を適用できます。

画面6 画面6 ディレクトリ構成が違うためファイル名の指定を促すメッセージが表示されている
画面7 画面7 パスを1つ分取り除くことでcsvディレクトリ下のファイルに差分を適用できた


筆者紹介

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

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のメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。