【zsh】 環境変数とは? 環境とは?
ホームディレクトリを指す HOME
, おなじみ PATH
, プロンプトを定義する PS1
, ...
我々は普段、さまざまな環境変数を扱っています。
環境変数を追加するときは、シェルのスタートアップファイル(e.g. ~/.zshenv
)にこんな感じで1行追加すると思いますが……
export MY_ENV_VAR='Hello,World'
いったい export
とはなんでしょうか? そもそもzshにおける環境変数とはなんでしょうか?
ふんわり理解しているようでいて、わからないことだらけ。
ちょっとだけ深掘りして整理していきたいと思います。
環境
- zsh 5.9 (homebrew)
- macOS Sequoia
変数とは
はじめにzshにおける変数の定義を整理します。
"Parameters"
我々が 変数 と呼んでいるものは、zshでは Parameters という概念の部分集合です(以降パラメータ)[1]。パラメータは名前と値、そして属性を持ち、名前が英数字またはアンダースコアで始まるものを特に variable = 変数と呼びます。
値は スカラ(文字列・数値),配列,連想配列 の3つに分類されます。このうちスカラパラメータについては name=value
の形式で名前と値を定義できます。
値を参照するには $name
とします。たとえば echo $param1
としたときは、param1
という名前を持つパラメータの値を取得し、引数として渡しています。
興味深いのは ?
もパラメータの一つである という点です。$?
は ?
という名前のパラメータ(≠変数)の値を参照しています。
パラメータの属性
属性の取得・編集にはzshのbuilt-in commandである typeset
を使用します[2]。
ちょっと面白い属性を設定してみましょう。ごく普通のスカラパラメータ param
を定義します。
% param='hello'
typeset
により属性 R
を追加します。この属性は引数をひとつ受け取ります。
% typeset -R 10 param
値を参照してみましょう。
% echo $param
hello
やや右詰めされた形で出力されました。属性 R
を持つパラメータは、その値を返すとき 属性に渡した文字数に合うよう先頭にスペースを付加します。実際の値は hello
のままです。
パラメータの属性情報を得るには -p
を指定します。
% typeset -p param
typeset -R10 E=hello
変数展開を用いて確認することも可能です。出力は少し異なります。
% echo ${(t)param}
scalar-right_blanks
環境変数とは
zshの変数についてなんとなくわかったので、次は環境変数について整理します。
export
が行う処理
zshでは export
は typeset -gx
と同じです[3]。
つまり、環境変数 = 属性 -g
, -x
をもつパラメータ ということになります。これら属性はそれぞれ以下のような効果を持ちます。
-g
The -g (global) means that any resulting parameter will not be restricted to local scope. (略)This flag does not affect the parameter after creation,(略)
-g (グローバル) は、結果のパラメータがローカル スコープに制限されないことを意味します。(略)このフラグは、作成後のパラメータには影響しません。
やや乱暴な言い方ですが -g
を設定することでグローバル変数にできます。定義段階からローカルスコープではないことを明示するための属性(という認識)です。
-x
Mark for automatic export to the environment of subsequently executed commands. (略)
後で実行されるコマンドの環境への自動エクスポートをマークします。
新しい概念が出てきました。 -x
を設定すると Mark for automatic export to the environment 、環境へのエクスポート対象となるようです。
属性 -x
を持つ変数を、とくに environment variables = 環境変数 と呼びます。
つながってきました。
エクスポートとは?
IEEE Std 1003.1-2024 (POSIX) によれば export
は 変数のエクスポート属性を設定 するコマンドと定義されています。この属性を付与された変数は、その後に実行されるコマンドの環境に含められます[4]。
環境
zshのマニュアルとPOSIXとで environment = 環境 という単語が共通して出てきました。
"Execution Environment"
IEEE Std 1003.1-2024 (POSIX) によれば、シェルは Execution Environment = 実行環境 を持ちます[5]。
ただ正直「実行環境とは?」と問われると返答に窮します。カレントディレクトリやパラメータ、関数、エイリアス、シェル自体のオプション(setopt
で設定するやつ) などを保持するコンテキスト……というのが近いでしょうか[6]。
環境とその複製
実行環境は基本的に閉じています。シェルからコマンド[7]を実行するとき、コマンドを呼び出すシェルと実行されるコマンドにはそれぞれ異なる環境が用意されます。
なので、こういうことはできません。これはエイリアスが環境間で引き継がれないからです。
% alias osname='uname -s'
% osname
Darwin
% echo 'osname' > script.sh
% chmod +x script.sh
% ./script.sh # シェルとは実行環境が異なる
./script.sh: line 1: osname: command not found
ただし source
や .
は現在の環境で実行 されます[8]:
% . ./script.sh
Darwin
% source ./script.sh
Darwin
サブシェル( ≠ 子プロセスとして実行されるシェル)の場合、現在の環境がコピー[9]されます。
% param=1
% ( # サブシェルで実行
subsh> echo $param # 複製元の環境で設定されたパラメータを参照
subsh> param=2 # 複製された環境内でパラメータを編集
subsh> echo $param # 編集後のパラメータを参照
subsh> )
1
2
% echo $param # サブシェルの環境はコピーなので、元の環境には影響しない
1
環境間で引き継がれる情報
先述の通り、シェルとそこから実行されるコマンドとはそれぞれ環境が異なります。
ただし いくつかの情報は引き継がれます [10]。
たとえばカレントディレクトリは引き継がれます:
% cd ~
% echo 'hello' > test.txt
% echo 'cat ./test.txt' > script.sh
% chmod +x script.sh
% ./script.sh
hello # カレントディレクトリに text.txt があるので、それを読んでいる
% cd /
% ~/script.sh
cat: ./test.txt: No such file or directory # / に test.txt は存在しない
そして エクスポート属性を持つ変数(=環境変数)もまた引き継がれます。
つまり PATH
に依存するシェルスクリプトが正しく動作するのは、シェルから環境を引き継ぐ際に環境変数の値がそのままコピーされるから……ということになります。
ただし 共有ではなく複製である という点に注意が必要です (サブシェルと似ています)。シェルスクリプト内で export
しても、実行元のシェルにはなんら影響はありません。
まとめ
zshにおいて……
- 変数は パラメータの一種 である
- パラメータは 名前, 値, 属性 をもつ
- エクスポート属性(
-x
)が設定された変数を特に 環境変数 という
-
export
は 属性に-x
を持つパラメータを定義 するコマンドである - プロセスは 環境 (実行環境)をもつ
- 環境はカレントディレクトリやシェル関数、パラメータなどを保持する
- コマンドを実行する際は 新たな環境が作成される
- エクスポート属性を持つ変数など、一部は 作成先の環境に引き継がれる
主な参照文献
- zsh: The Z Shell Manual
- The Open Group Base Specifications Issue 8 IEEE Std 1003.1™-2024 Edition
- 事前調査したスクラップ
-
2.13 Shell Execution Environment - Shell Command Language ↩︎
-
POSIXでは 特殊組み込みユーティリティを除くユーティリティ と定義されています ↩︎
-
一部例外があります(2.13 Shell Execution Environment を参照してください) ↩︎
-
2.13 Shell Execution Environment - Shell Command Language ↩︎
Discussion