本記事は、 シェルスクリプト Advent Calendar 2021 の 4日目 の記事だ。
そして、 且つ docker Advent Calendar 2021 4日目 の記事でもある。
どちらのカレンダーもまだまだスッカスカなので、禁じ手で埋めにかかってしまった。
Docker 公式イメージ などをベースにして、カスタムしてイメージをビルドして使おうとした際、 なるべくなら /etc/apt/apt.conf.d/
等のように、設定用のファイルを追加して、ツール側がいい感じにマージして利用してくれるのが望ましい。
しかし、 場合によってはやむを得ず、既存のファイルを sed
コマンドなどで編集せざるを得ないこともあるだろう。
カスタムイメージの Dockerfile をビルドする際に、当初は意図通り書き換えられていても、イメージが更新された結果、イメージのリビルド時にファイルの書き換えが意図しない結果となってしまう場合がある。 1
通常、 sed
コマンドは、置換が発生してもしなくても、 終了コード 0 で終了する。
このため、書き換えの成否にかかわらず、 docker build 時にエラーにならないため、コンテナ実行時に初めて置換が意図しない結果だったことに気づくことがある。
そこで、sed
コマンドの書き換えで適切なパターンが見つからなかった場合に 0以外の終了コードを返し、ビルド時にエラーとする方法を考える。
以下、 sed
は GNU sed を前提とし、 "行頭の foo" を BARfooBAR に置き換える場合の例。
まずは、 書き換えるパターンが見つからなかった場合に、エラーコードを返す方法。
sed -e '/^foo/{s//BAR\0BAR/;h};$!b;p;x;/./Q;Q16'
参考: https://stackoverflow.com/a/15966279
ざっとコマンドの流れを解説すると、以下のようになる。
{}
を用いて、正規表現に一致する行について以下を実行する。
$!b
の部分は、最終行でなければ次のサイクルに移動する。 すなわち、以降のコマンドは最終行でのみ実行される。さらに一歩踏み込んで、 書き換えるパターンが見つからない場合と、 2つ以上見つかってしまった場合両方で、エラーにする方法。
sed -e '/^foo/{s//BAR\0BAR/;x;/./Q32;g};$!b;p;x;/./Q;Q16'
基本的な動きは、ひとつもヒットしなかったパターンと同じだ。
ただ、ブロック {}
内部のコマンドを以下のように変更して、複数ヒットした場合にエラーで終了している。
{}
を用いて、正規表現に一致する行について以下を実行する。
なお、このコマンドは、 2つヒットした時点で出力が止まる。
モダンなプログラミング言語が軒並み型推論でコンパイル時にエラーとするように、 Dockerfile もビルド時にエラーにしてしまおう。
カスタムイメージの Dockerfile ベースイメージを選択する際、基本的にはタグである程度絞っておくべきだが、それはさておき。 ↩︎
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント