Linux / コマンド / env - 環境変数の設定とコマンドの実行

envは環境変数を確認したり、一部の環境変数を追加・変更・削除した状態でコマンドを実行するGNU Coreutilsのコマンドです。現在のシェルを直接変更せずに特定のプロセスだけに異なる環境を渡したいときに特に便利です。

引数なしで実行すると、現在渡されている環境を出力しますが、参照だけで十分な場合はprintenvの方が意図をより明確に示します。envの主な用途は「変更された環境でコマンドを実行する」ことです。

envコマンドとは?

プロセスは親プロセスから環境変数のセットを引き継ぎます。envはこのセットを元に変数を追加したり削除した新しい環境を構築し、指定したコマンドを実行します。変更内容は実行された子プロセスとその子プロセスに引き継がれる可能性がありますが、元のシェルの環境は変わりません。

基本的な文法

env [オプション] [名前=値]... [コマンド [引数]...]

コマンドを指定しない場合は、結果の環境を出力します。

env
env | sort

環境変数には機密情報が含まれる可能性があるため、出力全体を投稿、サポートリクエスト、または公開ログにそのまま貼り付けないでください。

一つのコマンドだけに環境変数を設定する

./start.sh と ./server は、ファイル・依存関係・実行権限を準備した自分のプログラムに置き換えます。names.txt も自分のテキストファイルを指定します。変数の意味や有効な値は受け取るプログラムが決めます。

env APP_ENV=production ./start.sh
env LANG=C sort names.txt

APP_ENVとLANGは、実行されるコマンドの環境にのみ適用されます。コマンドが終了した後、現在のシェルの同じ変数は新たに作成されたり変更されたりしません。

printenv APP_ENV

複数の変数を左から右の順で指定できます。

env HOST=127.0.0.1 PORT=8080 DEBUG=1 ./server

現在のシェルの代入文とenvの比較

POSIX系シェルでは、コマンドの前に直接名前=値を付けても、そのコマンドの環境を設定できます。

LANG=C sort names.txt
env LANG=C sort names.txt

外部プログラムを起動する env は、cd などのシェル組み込みコマンドや関数を直接呼ぶ道具ではありません。command の関数・組み込みコマンドの扱いと使い分けてください。単純な場合、2つの形式の結果は似ています。envは、環境を空にする、変数を削除する、作業ディレクトリを変更する、スクリプトインタプリタを検索するなどの追加機能が必要なときに便利です。

環境を空にして実行する-i

env -i /usr/bin/printenv

-iまたは--ignore-environmentは、既存の環境を無視して空の環境から開始します。再現性テストや隠れた環境依存性を見つけるときに便利ですが、PATH、HOME、ロケールや認証関連の変数まで消える可能性があります。

必要な変数だけを明示的に再度入れて実行できます。次の HOME="$HOME" の右辺は env の起動前に元のシェルで展開されます。-i は環境変数を除く機能であり、ファイルやネットワークの権限を分離する機能ではありません。

env -i PATH=/usr/bin:/bin HOME="$HOME" LANG=C /usr/bin/env

PATHがない場合、コマンドの検索に失敗する可能性があるため、絶対パスを使用するか必要なパスを一緒に指定してください。

特定の変数だけを削除する -u

以下は curl が認識する HTTPS_PROXY の削除例です。ただし https_proxy や ALL_PROXY などが残れば、それらが使われる可能性があります。変数一つの削除だけでプロキシを全面的に無効化したとは判断できません。curl は大文字 HTTP_PROXY をプロキシ設定として扱いません。curl のプロキシ環境変数も確認してください。

env -u HTTPS_PROXY curl https://example.com
env --unset=DEBUG ./start.sh

-u 名前 または --unset=名前 は指定した変数を結果の環境から削除します。プロキシ、デバッグ、またはテスト変数がプログラムの動作に与える影響を確認する際に使用できます。

変数を空の文字列に設定することと削除することは異なります。

env DEBUG= ./start.sh
env -u DEBUG ./start.sh

プログラムによっては「変数が存在するが値が空である」と「変数が存在しない」を異なる方法で処理する場合があります。

他のディレクトリで実行する -C

env -C /srv/app ./start.sh
env --chdir=/srv/app APP_ENV=production ./start.sh

GNU env の -C または --chdir は指定されたディレクトリに移動した後にコマンドを実行します。現在のシェルの作業ディレクトリは変更されません。このオプションは GNU 拡張であるため、移植性が必要なスクリプトではサポート状況を確認してください。

よく使うオプション

オプション 説明
-i, --ignore-environment 既存の環境を無視して、空の環境から開始します。
-u 名前, --unset=名前 結果の環境から指定した変数を削除します。
-C ディレクトリ, --chdir=ディレクトリ 指定したディレクトリに移動してからコマンドを実行します。
-S 文字列, --split-string=文字列 文字列を複数の引数に分割します。主にシバンで複数の引数を渡すときに使用します。
-0, --null 環境を出力するときに、改行の代わりにNUL文字で項目を区切ります。

サポートされているオプションはCoreutilsのバージョンによって異なる場合があります。配布版のenv --helpと公式マニュアルを併せて確認してください。

スクリプトの最初の行で /usr/bin/env を使用する

シバン(shebang)は、スクリプト先頭の #! で始まるインタプリタ指定行です。そこに /usr/bin/env を書くと、インタプリタをPATHで探すことができます。

#!/usr/bin/env python3

インタプリタはシステムごとに異なるパスにインストールされる開発環境で便利です。しかし、現在 PATH で最初に見つかるプログラムを実行するため、セキュリティと再現性が重要なシステムサービスでは、検証済みの絶対パスの方が適している場合があります。

複数のインタプリタ引数の渡し方

GNU Coreutils が -S をサポートする環境では、シバン文字列を複数の引数に分けることができます。

#!/usr/bin/env -S python3 -I

-S はすべてのオペレーティングシステムの env でサポートされる機能ではありません。配布対象のシステムを確認し、高い移植性が必要なら、対象環境に合うラッパースクリプトでインタプリタとオプションを明示する方法を検討してください。起動時のオプションを実行開始後の処理だけで代用できるとは限りません。例の Python の -I は隔離モードです。スクリプトのディレクトリやユーザーの site-packages を検索対象から外し、PYTHON で始まる環境変数も無視します。Python の -I オプションで条件を確認してください。

シェル変数と環境変数の違い

シェルに変数を作っても、自動的に子プロセスに渡されるわけではありません。

LOCAL_ONLY=value
printenv LOCAL_ONLY

export LOCAL_ONLY
printenv LOCAL_ONLY

export された変数のみが新しく実行されるプログラムの環境に含まれます。env は現在のシェル変数全体ではなく、渡された環境を基に動作します。

env と printenv の比較

区分 env printenv
主な目的 変更された環境でコマンド実行 環境変数の値を確認
全ての環境を表示 コマンドを省略すると可能 変数名を省略すると可能
特定の変数を確認 専用の形式がないためフィルターが必要です。 printenv HOMEのように直接確認します。
変数の追加・削除 サポートしています。 サポートしていません。
コマンド実行 サポートしています。 サポートしていません。

セキュリティと運用時の注意点

  • トークン、パスワード、秘密鍵のパスを含む環境をログに残さないようにします。
  • env 名前=値 コマンドに秘密値を直接記載すると、シェル履歴やプロセス情報に露出する可能性を検討する必要があります。
  • env -iでは証明書のパス、ロケール、プロキシ変数が抜けるため、動作が異なる可能性があります。
  • shebangの/usr/bin/envはPATHの影響を受けるため、実行主体と環境を信頼できるか確認してください。
  • サービス環境は可能であれば、サービスマネージャーの明示的な環境設定機能を使用します。

よくある質問

envで設定した変数は現在のターミナルに残りますか?

いいえ。env 名前=値 コマンドは実行したコマンドの環境のみを変更し、親シェルの変数は修正しません。

envとexportは何が違いますか?

exportは現在のシェルの変数を、今後起動する子プロセスへ渡す環境変数として指定します。envは一度のコマンド実行のための環境を構成するのに適しています。

env -iでコマンドが見つかりません。

既存のPATHまで削除されてしまった可能性があります。実行ファイルの絶対パスを使用するか、必要なPATHを明示的に設定してください。

参考資料