LinuxLinux [リナックス / ライナックス]オープンソースのOSカーネル環境において、「設定ファイル内のプレースホルダーを環境変数の値で一括置換したい」「アプリケーションのデプロイ時に、環境変数を使って設定ファイルを動的に生成したい」という課題に直面したことはないでしょうか。手動でファイルを書き換えるのはヒューマンエラーの原因になり、sed コマンドで複雑なエスケープ処理を行うのは手間がかかります。
envsubst コマンドを使用すると、環境変数を設定ファイルのテンプレートに展開し、環境に応じた設定ファイルを効率的に生成できます。置換対象の変数を明示することで意図しない変数の展開を抑止できますが、未定義変数が空文字になる点や、生成後の設定ファイルの構文検証、機密情報の取り扱いには注意が必要です。
この記事では、envsubst の基本的な使い方から特定変数に絞った安全な置換手順、DockerDocker [ドッカー]コンテナ型仮想化プラットフォームやシェルスクリプトでの実務的な活用法と注意点まで、インフラエンジニア向けにわかりやすく解説します。
確認した環境
本記事で紹介する手順は、以下の環境で動作確認を行っています。
- OSOS [オーエス]Operating System。基本ソフトウェア: UbuntuUbuntu [ウブントゥ]人気のLinuxディストリビューション 24.04 LTS / AlmaLinux 9.4
- ツール: gettext-base (envsubst) バージョン 0.21 以降
envsubstコマンドとは?ファイル内の環境変数を一括置換するツール
envsubst は、GNU gettext パッケージに含まれるコマンドラインツールです。標準入力から渡されたテキストやファイル内の環境変数参照(例: $VARIABLE や ${VARIABLE})を、現在のシェル環境変数に定義されている値に置換して標準出力に出力します。
テンプレートファイル(.template など)を用意しておき、実行環境に応じた変数を動的に埋め込む仕組みを作る場面で役立ちます。
envsubstのインストール方法(gettextパッケージ)
多くのディストリビューションでは、envsubst は gettext パッケージの一部として提供されています。環境にインストールされていない場合は、パッケージマネージャーを使用してインストールします。
Ubuntu / DebianDebian [デビアン]コミュニティ主導で開発される安定性の高いLinuxディストリビューション系の場合:
sudo apt updatesudo apt install gettext-baseAlmaLinux / Rocky Linux系の場合:
sudo dnf install gettextインストールが完了したら、バージョンを確認して正常に利用できることを確認します。
envsubst --versionenvsubstの基本的な使い方|標準入出力を使った置換
envsubst はデフォルトで標準入力を受け付けます。まずは、簡単な設定ファイルテンプレートを作成し、環境変数がどのように展開されるかを確認します。
ステップ1:サンプルとなるテンプレートファイルを作成する
カレントディレクトリに nginx.conf.template という名前でファイルを作成します。
server { listen 80; server_name ${DOMAIN_NAME};
location / { proxy_pass http://${BACKEND_HOST}:${BACKEND_PORT}; }}ステップ2:環境変数を設定してコマンドを実行する
シェル上で環境変数を一時的に定義し、ファイルを入力として envsubst を実行します。
export DOMAIN_NAME="example.com"export BACKEND_HOST="127.0.0.1"export BACKEND_PORT="8080"
envsubst < nginx.conf.template実行結果として、以下のように環境変数が展開された設定ファイルの内容が標準出力に表示されます。
server { listen 80; server_name example.com;
location / { proxy_pass http://127.0.0.1:8080; }}ファイルを直接上書き・保存するリダイレクトのコツ
envsubst 自体には、入力ファイルを直接書き換える機能(インプレース編集機能)はありません。そのため、置換結果を新しいファイルとして保存するには、シェル上のリダイレクト機能を使用します。
envsubst < nginx.conf.template > nginx.conf注意点として、入力ファイルと出力ファイルに同じファイルを指定する(例: envsubst < config.conf > config.conf)と、ファイルの中身が空になってしまう問題が発生します。これはシェルがリダイレクト先のファイルを先に初期化(トランケート)するためです。
元ファイルを安全に上書きしたい場合や、本番環境で稼働中の設定ファイルを更新する場合は、一度一時ファイルに出力して検証してから mv コマンドで置き換えるのが鉄則です。
本番環境で安全に設定ファイルを更新するスクリプト例
実務では、同時実行による競合を防ぐために mktemp コマンドで予測不能な一時ファイル名を生成し、終了時のクリーンアップ処理(trap)を組み合わせる構成が推奨されます。
#!/bin/bashset -euo pipefail
# 1. 対象ファイルと同じディレクトリに一時ファイルを作成TMP_FILE=$(mktemp ./nginx.conf.XXXXXX)
# エラー終了時や正常終了時に一時ファイルが残らないようクリーンアップを設定trap 'rm -f "$TMP_FILE"' EXIT
# 2. テンプレートから一時ファイルへ展開envsubst '$DOMAIN_NAME $BACKEND_HOST $BACKEND_PORT' \ < nginx.conf.template \ > "$TMP_FILE"
# 3. 必要に応じて置換後の設定ファイルを検証(構文チェック等)# nginx -t -c "$TMP_FILE" # ※構成やインクルード設定に応じて適切な検証方法を選択
# 4. 検証が通ったら本番設定ファイルへアトミックに置き換えmv "$TMP_FILE" nginx.conf[!TIP] 実務・本番環境での注意点
- パーミッションの確認:
mktempで作成した一時ファイルは、通常作成したユーザーのみが読み書きできる権限(600)になります。Webサーバーや別プロセスのユーザーが設定ファイルを読み取る必要がある場合は、mvの前にchmod 644 "$TMP_FILE"など用途に応じた適切なアクセス権限を設定してください。- 同一ディレクトリでの一時ファイル作成: 一時ファイルを
/tmpなど別パーティションに作成してしまうと、mvが同一ファイルシステム内のアトミックな inode 置換にならず、コピー&削除となって反映途中の不整合が生じる可能性があります。上記例のように対象ファイルと同じディレクトリ(./)内に一時ファイルを作成することで、安全なアトミック移動が行えます。
特定の環境変数のみを置換対象にする方法
オプションを指定しない場合、envsubst はテンプレートファイル内に存在するすべての環境変数形式の文字列を置換しようとします。しかし、設定ファイル内にアプリケーション独自のエスケープ記号や、シェル変数として展開したくないドル記号が含まれている場合、意図しない箇所まで置換されてしまうことがあります。
このような場合は、置換対象とする変数を引数(SHELL-FORMAT)として明示的に指定します。
envsubst '$DOMAIN_NAME $BACKEND_HOST' < nginx.conf.template > nginx.conf# またはブレース付きの形式でも指定可能envsubst '${DOMAIN_NAME} ${BACKEND_HOST}' < nginx.conf.template > nginx.confこのように変数をスペース区切りで指定することで、指定した変数のみが置換され、その他の変数はそのままの形式で維持されます。変数の指定形式は $VARIABLE と ${VARIABLE} のどちらでも問題ありません。
特に注意したいのが、引数をシングルクォート '...' で囲む点です。ダブルクォート "..." で囲んでしまうと、envsubst に渡る前にシェル自身が変数を展開してしまい、意図した動作になりません。
また、この引数指定は NginxNginx [エンジンエックス]高性能なWebサーバー・リバースプロキシ の設定ファイルを扱う際にも極めて重要です。Nginx の設定ファイル内には、$host、$remote_addr、$request_uri などの Nginx 組み込み変数が頻繁に記述されます。引数を指定せずに envsubst を実行してしまうと、これらの Nginx 変数まで「未定義のシェル環境変数」として空文字に置き換わってしまい、設定ファイルが破損して起動エラーの原因になります。
[!IMPORTANT] 生成後の構文チェックを必ず行う 置換対象を限定することは意図しない置換を抑止するための対策であり、生成された設定ファイルの内容が文法的に正しいことまでを保証するものではありません。環境変数の値に予期せぬ文字列が含まれている可能性もあるため、Nginxであれば生成後に必ず
nginx -tコマンドを実行するなど、各ミドルウェアに応じた構文テストを行う手順を組み込みましょう。
テンプレート内の環境変数を一覧表示する(-v / —variables)
テンプレートファイル内でどのような環境変数が参照されているかを事前に確認したい場合は、-v(または --variables)オプションを使用します。
このオプションは環境変数を展開するためのものではなく、渡された文字列に含まれる変数名のみを列挙して標準出力に出力する機能です。なお、-v(--variables)オプションを指定した際は標準入力が無視される仕様になっているため、以下のようにコマンド置換 $() を使ってテンプレートファイルの内容を引数として渡します。
envsubst --variables "$(cat nginx.conf.template)"実行すると、テンプレート内で参照されている環境変数名が1行ずつ出力されます。
DOMAIN_NAMEBACKEND_HOSTBACKEND_PORT[!NOTE]
-vオプションを利用する際の注意点
- 重複出力: テンプレート内で同一の変数が複数回使われている場合、変数名が重複して出力されます。重複を除去してユニークな一覧を取得したい場合は、次のように
sort -uとパイプで連結して処理します。Terminal window envsubst --variables "$(cat nginx.conf.template)" | sort -u- Nginx組み込み変数も抽出される: テンプレート内に
$hostなどの Nginx 組み込み変数が記述されている場合、それらもシェル変数と同じ構文とみなされて抽出結果に含まれます。- 引数サイズの制限: テンプレート全体をシェルのコマンドライン引数として渡すため、ファイルサイズが非常に大きい場合は OS の引数長上限(
ARG_MAX)に注意が必要です。- 変数の定義チェックには追加処理が必要:
-vコマンド単体は「テンプレートに書かれている変数名」を出力するだけであり、それらが現在のシェル環境で実際に定義されているかまでは確認しません。また、シェル内で変数がセットされていてもexportされていなければenvsubstからは参照できません。必須変数が漏れなく定義されているかを検証したい場合は、抽出した変数名をループで回して実際の環境変数と照合する処理が必要です。
実務で使える!シェルスクリプトやDockerでの活用事例
envsubst は、インフラストラクチャの構築やコンテナデプロイの現場で幅広く活用されています。
シェルスクリプトでの動的な設定ファイル生成
デプロイ用のシェルスクリプトに組み込むことで、環境ごとの差異を吸収する柔軟な構成管理が可能になります。
#!/bin/bashset -euo pipefail
TEMPLATE="/etc/myapp/config.json.template"OUTPUT="/etc/myapp/config.json"
# 1. テンプレートファイルの存在確認(存在しなければエラー終了)if [ ! -f "$TEMPLATE" ]; then echo "Template file not found: $TEMPLATE" >&2 exit 1fi
# 2. 必要な環境変数が設定されていることを確認(未設定または空文字ならエラー終了): "${DATABASE_URL:?DATABASE_URL is required}": "${API_TIMEOUT:?API_TIMEOUT is required}"
# 3. テンプレートから設定ファイルを生成(特定の変数のみ安全に展開)envsubst '$DATABASE_URL $API_TIMEOUT' \ < "$TEMPLATE" \ > "$OUTPUT"
echo "Configuration file generated successfully."[!IMPORTANT] 未設定変数の空文字化とシェル側でのチェック
envsubstは置換対象の変数が未定義であってもエラーを出さず、通常は「空文字列」に置換して処理を完了します。そのため、設定が空のまま不完全な設定ファイルが生成されるのを防ぐには、上記スクリプトのように先にテンプレートの存在を検証したうえで、シェル側で必須変数の存在チェック(: "${VAR:?message}"など)を事前に行うことが重要です。 ※なお、>による直接上書きでは処理中にエラーが起きた際に出力先が壊れる可能性があるため、本番環境では前述の一時ファイル(mktemp)を使った更新方式の併用も検討してください。
[!NOTE] .envファイルの読み込みとJSONJSON [ジェイソン]JavaScript Object Notation。軽量データ交換フォーマット/YAMLYAML [ヤムル]YAML Ain't Markup Language。設定ファイルなどに使うデータフォーマット構文についての注意
- .env の安易なパースを避ける:
.envファイルをexport $(cat .env)やgrep | xargsでシェルに読み込ませる方法は、値に空白や特殊文字(接続URLURL [ユーアールエル]Uniform Resource Locator。Webページのアドレスや記号入りパスワード)が含まれると分割・破壊されるリスクがあります。実務では Docker Compose のenv_file機能や、アプリケーション側の dotenv パーサーを利用することが推奨されます。- JSONやYAMLの構文破壊:
envsubstは単純な文字列置換を行うため、値にダブルクォートやエスケープシーケンス、改行が含まれると、出力された JSON/YAML の文法が壊れてパースエラーになる場合があります。複雑な構造化設定を動的生成する場合は、jqやyqなど専用のツールを併用すると安全です。
Dockerコンテナ起動時での活用
Dockerコンテナの運用では、設定値を環境変数として渡し、コンテナ起動時に設定ファイルを動的生成する方法が広く利用されています。これにより、環境ごとに異なる設定値をコンテナイメージに直接固定せずに管理できます。
パターン1: Nginx公式イメージの標準機能を活用する(推奨)
Nginx公式Dockerイメージには、コンテナ起動時に設定テンプレートを展開する仕組み(/docker-entrypoint.d/20-envsubst-on-templates.sh)が標準で用意されています。
そのため、自前で CMD や起動シェルスクリプトを記述する必要はなく、/etc/nginx/templates/ ディレクトリ配下に .template 拡張子で配置するだけで自動的に展開されます。
FROM nginx:alpine
# ポート番号のデフォルト値を定義(未指定時の空文字エラーを防止)ENV PORT=80
# テンプレートファイルを公式指定のディレクトリへ配置COPY default.conf.template /etc/nginx/templates/default.conf.template置換対象とする環境変数を絞り込みたい場合は、コンテナ起動時に環境変数 NGINX_ENVSUBST_FILTER に正規表現を指定します。
# PORT のみを完全一致で対象にする場合docker run -d -p 80:80 \ -e PORT=80 \ -e NGINX_ENVSUBST_FILTER='^PORT$' \ my-nginx-image
# 複数変数を対象にする場合(例: PORT と DOMAIN_NAME)# -e NGINX_ENVSUBST_FILTER='^(PORT|DOMAIN_NAME)$'コンテナが起動すると、自動的に /etc/nginx/conf.d/default.conf が生成され、Nginx本体が起動します(コンテナ内部では nginx -g 'daemon off;' によりフォアグラウンド動作します)。なお、フィルターを指定した場合でも、環境変数の値が Nginx の構文として正しいかどうかまでは検証されないため、値の形式には注意してください。
パターン2: 汎用コンテナ(独自イメージ)でエントリーポイントを使う場合
Nginx以外の独自コンテナ(AlpineAlpine [アルパイン]Dockerイメージなどでよく使われる、超軽量かつセキュアなLinuxディストリビューションやUbuntuベースの自作アプリなど)で envsubst を実行したい場合は、コンテナのエントリーポイントスクリプト(docker-entrypoint.sh)の中で実行するのが一般的です。
docker-entrypoint.sh:
#!/bin/shset -e
# テンプレートから設定ファイルを生成(特定変数のみ展開)envsubst '$DATABASE_URL $PORT' < /app/config.json.template > /app/config.json
# CMDで渡されたメインプロセスを実行(シグナルハンドリングを維持)exec "$@"Dockerfile:
FROM alpine:latest
# gettextパッケージをインストール(※より軽量化したい場合は単体パッケージの apk add --no-cache envsubst も利用可能)RUN apk add --no-cache gettext
WORKDIR /appCOPY config.json.template /app/config.json.templateCOPY docker-entrypoint.sh /docker-entrypoint.shRUN chmod +x /docker-entrypoint.sh
ENTRYPOINT ["/docker-entrypoint.sh"]CMD ["./my-app"]exec "$@" を使用することで、プロセスID(PID 1)がメインプロセスに引き継がれ、Dockerの停止シグナル(SIGTERM)を適切に受け取れるようになります。
[!CAUTION] 機密情報(クレデンシャル)の取り扱いについて 環境変数を利用することでパスワードなどの機密情報をコンテナイメージに直接埋め込むことは回避できます。しかし、環境変数は
docker inspectや実行環境のプロセス一覧などから閲覧されるリスクがあり、生成された設定ファイルもコンテナのファイルシステム上に平文で残ります。厳格なセキュリティが要求される環境では、Docker Secrets や KubernetesKubernetes [クーバネティス / クベルネテス]コンテナオーケストレーションシステム Secrets、適切なファイルパーミッション管理を組み合わせることを検討してください。
まとめ:envsubstで設定ファイルのテンプレート化を効率化しよう
本記事では、envsubst コマンドを使用したファイル内の環境変数一括置換について解説しました。
envsubstは gettext パッケージに含まれる、ファイル内の環境変数を展開・置換するためのコマンドラインツールである。- 標準入力から受け取ったテンプレートに対し、シェルの環境変数を埋め込んで標準出力へ出力できる。
- インプレース上書きはできないため、一時ファイルと
mvコマンドを組み合わせて安全にファイルを保存する。 - 引数に置換対象の変数名を明示することで、Nginxの組み込み変数(
$hostなど)の意図しない消失を防止できる。 envsubst自体は未定義変数を空文字にしてしまうため、シェル側での必須チェックや、生成後の構文チェック(nginx -t等)を組み合わせることが実務では重要である。- Nginx公式Dockerイメージのテンプレート機能(正規表現フィルター)や独自エントリーポイントを活用することで、コンテナデプロイを柔軟に自動化できる。
設定ファイルの管理やデプロイプロセスの自動化において、envsubst は軽量で非常に強力なツールです。本記事で紹介した安全性への配慮や注意点を押さえながら、日々のインフラ運用やコンテナ構築にぜひ役立ててください。
以上で本記事の解説を終わります。
よいITライフを!
人気記事
- 1
- 2
- 3
- 4
- 5
Rocky Linux対応。実際にWebサーバーを公開するまでのプロセスを体験できる、最も確実で実践的なガイドブックです。