「環境変数」がよくわかってないので、そろそろざっくりレベルでは理解しておく


「登場人物」と「誰が誰と何をしているか」の理解を重視します。

# 環境変数とは
その名のとおり、環境が使う変数。

## 環境とは
**環境** とは、プログラムが動作する何らかの単位のこと。

英語では Environment と書く。Env と略すことが多い。

以下を全部含む。

- 1 コマンドやスクリプト
- 2 アプリ
- 3 ミドルウェア
- 4 PC、サーバー、コンテナ、仮想マシン、インスタンスといった「一台」分
- 5 n台のサーバーと、その他ネットワークなどインフラを含んだシステム全体

ただし、この文脈では 4 以前を指す。

## 変数とは
**変数** とは、何らかの情報を入れておくもののこと。

英語では Variable と書く。Var などと略すことがある。

変数には名前（変数名）と情報（値）があり、名前に対して情報を入れる、という書き方をする。

```
JAVA_HOME=D:\languages\java\jdk-17.0.7
```

これは `JAVA_HOME` という名前の変数に、`D:\languages\java\jdk-17.0.7` という情報を入れている。これを表現すると、次のようになる

- 変数名 JAVA_HOME の変数に、
- D:\languages\java\jdk-17.0.7 という値を入れている

同様に、特定の情報を取り出すときも、変数名を指定すると、その変数名（が持つ値）が届けられる。

これはコンピュータ上の基本的な仕組みであり、そういうものと受け入れるしかない。数学で使う数式とは違うが、数学は無視していい。`var1=xxx`と書いたら、これはvar1にxxxという情報を入れます、という意味なのだ。

## 環境変数とは
環境が使う変数である。

コマンドやスクリプトも、アプリも、ミドルウェアも、またまたサーバーなど「1台のコンピュータ」も、どれも **環境変数という情報源を使えるようになっている**。そういう仕組みだ。

情報を持たせたり書き換えたりする仕組みは色々あるが、環境変数もその一種となる。特に環境変数はそれら環境とは独立した機構であるため、環境も、環境を使う私たち自身も、自由に環境変数にアクセスできる。

以下はイメージ。

![20241005_122945.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896888/0a9d98de-ea97-ac29-d23d-44b619c89d82.jpeg)

たとえば以下のような使い方をする。

- 1: アプリの挙動を設定に応じて変えられるようにしておく
- 2: その設定は、環境変数 XXX から読み込むようにする
- 2: アプリの開発者は、状況に応じて XXX の値を書き換えてからアプリを起動する

こうすれば **アプリ自体に手を加えることなく**、設定を（環境変数 XXX 経由で）変えるだけでアプリの挙動を変えられる。バカ真面目に「挙動を変えたいのでアプリを作り直します」なんてしなくてもいいわけだ。

# 環境変数の細かい性質
ここからもう少し細かい仕組みや制約の話に入る。

## 環境変数は「いつ」読み込まれるのか
これは単純で、**環境を起動したとき** である。

しかし、段階的である。詳しく見ていく。

まずサーバーの単位（厳密には OS）では、起動時にすべての環境変数を読み込む。というより **環境変数という仕組みは OS の機能** なので、OS を起動したときに使えるようになるのはまあ当然である。

次に、各種プログラム（スクリプトもアプリもミドルウェアも全部含む）は、**起動した時点** での環境変数の値を **コピーして保持する**。以下のイメージ。このアプリは起動して一度読み込んだ後は、2: のコピーの方を見る。

![20241005_124654.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896888/bb3e9177-b880-97f4-7a88-ca5a38e8708a.jpeg)

なのでアプリから環境変数 abc や def を書き換えても、元の 1: の方は汚されない。コピーしたものなのでご自由に使えばいい。情報を保存する手段として環境変数を使うことは通常しない。とはいえ、環境変数は、あくまでも起動時に外から設定を取ってくるためのものである。起動時にコピーを保持できれば十分だ。

で、ここからがややこしいのだが、アプリからさらに別のプログラムを起動するとしよう。スクリプトを実行するでもいいし、別のアプリ2を起動する、でもいい。仮にスクリプトを実行するとしよう。このとき、スクリプトから見える環境変数はどうなっているか。わかりづらいので、アプリ側で abc を 11111 に変えていたとしよう。以下の構図だ。

![20241005_125333.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896888/dcc41c83-377c-87d5-b4a1-cdee028aa102.jpeg)

このとき、スクリプトから見える環境変数はどうなるのか。

答えは **「自分を起動したやつが持っている分」を「コピーして保持する」** である。

![20241005_125604.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896888/607a8450-7d6a-e78c-6636-78fd5c497e2d.jpeg)

これを **伝搬** と呼んだりする。OS の分ではなく、自分を実行したやつ（親）の分をコピーするわけだ。

## グローバルとローカル
一般的な話をすると、環境変数のあり方は 2 種類ある。

OS の設定として存在する大本を **グローバル** という。

アプリやスクリプトなど、各プログラムが持っている分を **ローカル** という。

![20241005_130038.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896888/20a1c31a-0c44-52b0-b8d9-1f585485bab5.jpeg)

## ローカルを持ってるけど、グローバルも見れる
ややこしいが、プログラムは自分のローカルの分のみならず、大元のグローバルの分を別途見に行くこともできる。

![20241005_130314.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3896888/f8b93db8-8f61-ff03-94a7-0a6ff365f9dc.jpeg)

ただし、上図でバツを示しているとおり、自分を実行した親のローカルを見ることはできない。もっというと、**プログラムは自分以外のローカルを見ることができない**。

OS レベルでは見れる。アプリのローカルも、スクリプトのローカルも、OS が使える人であれば見ようと思えば見れる。

# おわりに
これで環境変数がどこでどうなっているかというイメージは湧いたと思う。