シェル変数と環境変数
Unix 系の OS で一般に環境変数と呼ばれているものには、実は有効範囲の異なるものが 2 種類ある。
- シェル変数 : そのシェルの中から実行される環境だけで有効な環境変数
- 環境変数 : シェル変数の範囲に加え、そのサブシェルへも引き継がれる
シェル変数と環境変数の設定方法は、シェルによって異なる。
操作 | sh 系 | csh 系 |
---|---|---|
シェル変数設定 | VAR=VALUE | set VAR VALUE |
シェル変数削除 | unset VAR | unset VAR |
シェル変数一覧表示 | set | set |
環境変数設定 | VAR=VALUE; export VAR or export VAR=VALUE |
setenv VAR VALUE |
環境変数削除 | unset VAR | unsetenv VAR |
環境変数一覧表示 | printenv | printenv |
この表からも分かるように、 sh 系ではシェル変数をベースに公開指定 (export 指定) したものを環境変数と呼んでいるだけであるが、 csh 系ではシェル変数と環境変数が明確に区別されている。
コマンドライン実行と環境変数 (bash編)
まず、シェル変数を定義して見え方を調べてみる。 set はシェル変数を、 printenv は環境変数を表示する。だから、次の例では 4 行目の printenv 実行後に何も表示されない。 VAR1 を export して環境変数へ昇格すれば、 set からでも printenv からでも VAR1 が参照可能になる。
$ VAR1=VALUE1 $ set | grep VAR1 VAR1=VALUE1 $ printenv | grep VAR1 $ export VAR1 $ set | grep VAR1 VAR1=VALUE1 $ printenv | grep VAR1 VAR1=VALUE1
一時的な環境変数をコマンドに渡す実験。コマンドの手前に変数の定義を置くと、そのコマンド実行中にだけ有効な環境変数を定義できる。これは bash の機能である。しかし次の例では、 1 行目で set コマンドへ向けてこれを実行しても何も表示しない。ではこれを bash に頼らず env コマンドで実行するのが 2 行目の例だが、ここでエラーが発生する。実は、 set コマンドは bash の内部コマンドなので、 env が解釈できないのである。
$ VAR2=VALUE2 set | grep VAR2 $ env VAR4=VALUE4 set | grep VAR4 env: set: No such file or directory
従って、独立なコマンドである printenv を使えば、期待通りの結果を得る事ができる。 env を使わない場合 (1 行目) でも printenv が値を表示できている事から、これがシェル変数では無く、環境変数である事が分かる。
$ VAR3=VALUE3 printenv | grep VAR3 VAR3=VALUE3 $ env VAR4=VALUE4 printenv | grep VAR4 VAR4=VALUE4
NOTE : env コマンドは、引数を付けないと printenv コマンドと同じ動作になる。また、 env コマンドへオプション – (ハイフン) を付けると、明示的に指定した物以外の環境変数が消された状態でコマンドが走る。
シェル変数の有効範囲の実験。シェル変数はサブシェルへ継続されないので、 4 行目で起動したサブシェル内では set が何も表示しない (5 行目) 。サブシェルから元のシェルへ戻ってくれば、また復帰する (6 〜 8 行目) 。
$ VAR5=VALUE5 $ set | grep VAR5 VAR5=VALUE5 $ bash $ set | grep VAR5 $ exit $ set | grep VAR5 VAR5=VALUE5
一方、環境変数はサブシェルへも引き継がれる。
$ export VAR6=VALUE6 $ set | grep VAR6 VAR6=VALUE6 $ printenv | grep VAR6 VAR6=VALUE6 $ bash $ set | grep VAR6 VAR6=VALUE6 $ printenv | grep VAR6 VAR6=VALUE6 $ exit $ set | grep VAR6 VAR6=VALUE6 $ printenv | grep VAR6 VAR6=VALUE6
make と環境変数
以下の様な Makefile を用意する。暗黙定義の make 変数 CC と、自作した make 変数 DIR のふたつを用意し、 make のコマンドラインで指定する環境変数がこれら make 変数へ与える影響を見る事にする。
DIR=/tmp all: @echo $(CC) @ls $(DIR)
make コマンドの手前に環境変数 CC 定義を置くと、 Makefile の中の make 変数 CC が上書きされる事が分かる (2 行目) 。
$ CC=Overwritten1 make Overwritten1 CRX_75DAF8CB7768 kokubu pulse-2L9K88eMlGn7 ssh-nMPmZIIi1384 acroread_1000_1000 orbit-gdm pulse-CcctT9RwKSB1 sylpheed-1000 keyring-sdi1lH orbit-kokubu pulse-PKdhtXMmr18n
同様に env を使っても同じ結果が得られる (2 行目) 。
$ env CC=Overwritten2 make Overwritten2 CRX_75DAF8CB7768 kokubu pulse-2L9K88eMlGn7 ssh-nMPmZIIi1384 acroread_1000_1000 orbit-gdm pulse-CcctT9RwKSB1 sylpheed-1000 keyring-sdi1lH orbit-kokubu pulse-PKdhtXMmr18n
make コマンドの引数として CC の定義を与えても同じ結果を得る。しかし、この挙動は環境変数とは無関係であり、単に make コマンド自体が持つ変数置換機能である (2 行目) 。
$ make CC=Overwritten3 Overwritten3 CRX_75DAF8CB7768 kokubu pulse-2L9K88eMlGn7 ssh-nMPmZIIi1384 acroread_1000_1000 orbit-gdm pulse-CcctT9RwKSB1 sylpheed-1000 keyring-sdi1lH orbit-kokubu pulse-PKdhtXMmr18n
次に Makefile の中へ自分で定義した make 変数 DIR を対象に同じ事を実験してみる。環境変数は DIR へ影響を与えられない (3 〜 5 行目、 9 〜 11 行目) 。
$ DIR=/var make cc CRX_75DAF8CB7768 kokubu pulse-2L9K88eMlGn7 ssh-nMPmZIIi1384 acroread_1000_1000 orbit-gdm pulse-CcctT9RwKSB1 sylpheed-1000 keyring-sdi1lH orbit-kokubu pulse-PKdhtXMmr18n $ $ env DIR=/var make cc CRX_75DAF8CB7768 kokubu pulse-2L9K88eMlGn7 ssh-nMPmZIIi1384 acroread_1000_1000 orbit-gdm pulse-CcctT9RwKSB1 sylpheed-1000 keyring-sdi1lH orbit-kokubu pulse-PKdhtXMmr18n
しかし make コマンドの引数、つまり make コマンド自体の make 変数置換機能は利用可能である (2 行目) 。
$ make DIR=/var cc backups cache crash games lib local lock log mail opt run spool tmp www
これまでの実験により、環境変数と make 変数、 make コマンドの挙動にはルールがある事が分かる。実は make コマンドが make 変数を置換する際に優先順位があり、それは以下の様になっている (優先順位が低い順) :
- 暗黙定義の make 変数
- make コマンド実行時の環境変数
- Makefile の中で明示的に値を代入している make 変数
- make コマンドの引数で置換指定した make 変数
また、この評価順序は make コマンドへオプション -e を与える事で一部変更可能だが、残念ながら行儀が悪い行為とされている (らしい) 。