LoginSignup
206
231

More than 3 years have passed since last update.

Windows環境変数の超基本を理解する為のアプローチ

Last updated at Posted at 2019-03-01

対象読者

  • 「環境変数」というよくわからないものに対して、何となくイメージをつかみたい方。
  • プログラム言語(なんでもよい)の「変数」というものを何となく知っている方。

前置き

本稿では「環境変数」の「基本仕様」と「基本的な取り扱い方」について
OSを「Windows」に絞って説明します。
OSのエディションは「Windows10 Pro」、
OSのバージョンは「April 2018 Update(1803)」に準拠します。

また、説明文中・文末の「*数字」は脚注へのリンクです。
(qiitaの脚注Markdownはどうにも扱いきれなかったので自前です)
本筋にはあまり影響のない部分を脚注として補足しています。

環境変数とは

環境変数(かんきょうへんすう、英語: environment variable)はオペレーティングシステム (OS) が提供するデータ共有機能の一つ。
OS上で動作するタスク(プロセス)がデータを共有するための仕組みである。
特にタスクに対して外部からデータを与え、タスクの挙動・設定を変更するために用いる。
出典:Wikipedia

「OSが提供する」と記載されている通り「Windows」だけでなく「UNIX」や「Linux」にも存在する機能です。
では「データ共有機能ってなんじゃらほい?」となるわけですが要は「変数」です。*1

例えば、こんな感じ。
「住所(address)」という名の変数には、「町名」や「番地」など「住所という属性値を特定する記号」が入っています。

Java
String address = "東京都◎◎区△△町1-1-1";
System.out.println(address);
#「東京都◎◎区△△町1-1-1」を標準出力に表示する
Python(3.x)
address = '東京都◎◎区△△町1-1-1'
print(address)
#「東京都◎◎区△△町1-1-1」を標準出力に表示する
Javascript
let address = "東京都◎◎区△△町1-1-1";
console.log(address);
#「東京都◎◎区△△町1-1-1」をブラウザコンソールに表示する

「環境変数」もまた普通の「変数」と同様に
「変数名」と「値」というペアで存在し、「変数名」で参照すると「値」が引ける

普通の「変数」そのままです。

以下のWindowsバッチでは上記のプログラムと同様に
「ADDRESS」という環境変数に値をセットし、そして表示させています。
(プログラムソースの詳しい説明はのちほど)

Windowsバッチ
SET ADDRESS=東京都◎◎区△△町1-1-1
ECHO %ADDRESS%
# 「東京都◎◎区△△町1-1-1」を標準出力に表示する

とは言っても「環境変数」には普通の「変数」のように
「データ型」や「オブジェクト」といった込み入った属性・特性はありません。
OSとしてのデータ共有機能として提供されるのは
原則、「変数名」と「値」のシンプルな組み合わせのみです。

また「値」としては「文字列」を格納する機会が多いので
「環境変数」は「文字列値を格納する変数」という認識で最初はよいかと思います。

「変数」の超基本的な概念

それでは「環境変数」の説明をしていきたいと思うのですが、
その前に一般的な「変数」の超基本をさっと説明させて頂きます。
大事なことなので。

「環境変数」のみならず、「変数」で一番大事な概念は何より「名実一体」であることです。
「名は体を表さ」なくてはいけないのです。

上記例で言えば「住所(address)」という変数には「住所という属性値を特定する記号」が必ず入ってなくてはいけません。

逆に言えば、「住所という属性値を特定する記号」を入れるための「変数」が「住所(address)」である、という事です。

以下はダメです。

Java(ダメな例)
//「住所」に「年齢」を入れている
String address = "40歳";
Java(ダメな例)
//「住所」があいまい(「エリア」とか「地域」とかそういう言葉で括るべき)
String address = "関東地方";

何故、ダメかはおわかりになるでしょうか?

「変数は宣言した時点で役割を持つ」からです。

そしてその「変数」のライフサイクルによっては、
「宣言する人」と「値を入れる人」と「参照する人」が異なる場合もあります。

例えば、郵便局の配達員は指定された「住所」を参照して郵便物を届けますよね?
その「住所」に「40歳」って書かれてたら「えぇ・・・」ってなるじゃないですか。

つまり、「発送する人」がモノを郵送する際に指定する「住所」は
「その郵便物が届けられるべき場所を郵便局員が特定する情報」という
役割」を与えられている、ということです。

郵便局が「宣言する人」、発送者が「値を入れる人」、カブで配達する配達員が「参照する人」です。

「住所に40歳と記載された郵便物」は
プログラムへそのまま置き換えるなら、紛う事なき「バグ」です。*2

郵便の流れは上記の通り、誰が何をしたかというのがわかりやすいのですが
実際のプログラミングの現場では
「誰がこんな値を入れたぁ!?お前か?
という事態が往々にして発生します。
これはいけません。

またプログラム上で宣言された「変数」も、
「郵便物」の一つとは限らず、大量の「変数」が宣言されているかもしれません。
だからこそ、一つ一つの「変数」は意識して宣言するべきです。*3

色々なプログラム言語を触るようになって「変数」といわれると
ついつい「宣言できるデータ型の特性」や言語独自の「変数のお作法」に目がいきがちになってしまいますが
「変数」の基本は「名実一体」です。
覚えておいてください。

環境変数の種類

それではまず始めに「環境変数の種類」です。
Windowsには大きく分けて「システム環境変数」と「ユーザ環境変数」の2種類があります。

その中でも、システム環境変数「PATH」およびユーザ環境変数「PATH」は
特殊な環境変数なので後で別途、説明します。

システム環境変数

 「システム環境変数」とは「OS(Windows)が持っている変数」です。
 「システム環境変数」はどのユーザであっても「参照」する事ができます。
 ただし、「作成」「編集」「削除」の操作に当たっては「Windowsの管理者権限」が必要です。

ユーザ環境変数

 「ユーザ環境変数」とは「OS(Windows)へログオンしたユーザが持っている変数」です。
 「ユーザ環境変数」は「OS(Windows)へログオンしたユーザ」のみが「参照可能」です。
 「ユーザ環境変数」はユーザであれば「作成」「編集」「削除」が可能ですが
 他ユーザの環境変数へはアクセスできません。
 (Aさんが作成したユーザ環境変数にBさんはアクセスできません)

環境変数の一意性

 「ユーザ環境変数」の中で同じ変数名を宣言することはできません。
 同様に「システム環境変数」の中でも同じ変数名を宣言することはできません。
 ただし「ユーザ環境変数」と「システム環境変数」での変数名重複は許容されています。

 「ユーザ環境変数」にも「システム環境変数」にも同じ変数名が存在した場合、
 「管理者権限でのインスタンス」また「環境変数PATH」の場合を除いて
 「ユーザ環境変数」を優先して参照します。
 (「管理者権限でのインスタンス」、「環境変数PATH」はのちほど説明します)

環境変数の記述方法・体裁

 「変数名」は慣例上、全て「半角大文字」で定義するのが普通です。
 「OS」「HOMEDRIVE」「USERNAME」「PATH」など。
 
 ただし、「半角小文字のみ」や「半角大文字小文字混在」も許容します。
 「windir」「SystemDrive」など。

環境変数の振る舞い(まとめ)

 「ユーザ環境変数」と「システム環境変数」の振る舞いをまとめると以下の通りです。

  1. システム環境変数としてのみ宣言している変数は管理者権限がなくてもアクセスが可能。

  2. システム環境変数とユーザ環境変数には同じ変数名を指定できる。

  3. システム環境変数とユーザ環境変数に同じ変数名があった場合、
    ユーザ環境変数を優先して参照する。
     (ただし管理者権限でのインスタンスは除く)
     (ただし環境変数PATHを除く)

環境変数の設定ダイアログを開く方法

 環境変数を実際にいじっていこうとなった際には
 環境変数の設定画面である「環境変数の設定ダイアログ」をそこそこ頻繁に開くことになりますので、
 「環境変数の設定ダイアログを開く優良手順」(*4)をご紹介させて頂ければと思います。

  1. Windowsキー+I(アイ)で「Windowsの設定」画面を開く。
  2. 「環境」と打つ。
  3. 「環境変数を編集」と「システム環境変数の編集」がサジェストされる
  4. 「環境変数を編集」もしくは「システム環境変数の編集」を選択する。

マウス操作不要です。

ちなみに、操作者(ログオンユーザ)に管理者権限がなくても
「環境変数を編集」によって「環境変数」ダイアログは開きますが
「システム環境変数」の「新規」「編集」「削除」ボタンはグレーアウトしており、
それぞれの操作はできない状態になっています。
 (「ユーザ環境変数」は普通に編集可能です。)

環境変数をいじった後にすべき事

 環境変数を「新規」で作成したり、「編集」したり、「削除」したりした後は
 「インスタンス」を新たにする必要があります。

インスタンスって何?

 以降「DOSプロンプト」を舞台にして説明していきます。
 環境変数を新規に作成したり、現状の環境変数を確認したり、といった簡単な参照には
 DOSプロンプトを使うのが最初の一歩です。
 「俺はpowershellが最初の一歩だったし…」という方も一旦、powershellは忘れてください。

 「DOSプロンプト」は「DOS窓」だったり「コマンドプロンプト」(*5)だったりと呼ばれている
 「Windowsキー+Rを押してcmd」で起動する例のアレです。

 では早速「DOSプロンプト」を「Windowsキー+Rを押してcmd」で起動してみてください。
 そこで「cmd」のヘルプを見てみます。

DOSプロンプト
C:\>cmd /?
Windows コマンド インタープリターの新しいインスタンスを開始します。
(中略)

 冒頭の説明により「cmd」というコマンドは
 「(インタプリタという何かの)新しいインスタンスを開始」するコマンドだという事がわかります。
 この「インスタンス」が「環境変数をいじった後に新たにすべきインスタンス」です。
 視覚的に「インスタンス=DOSプロンプトのウインドウ」という認識でOKです。(*6

インスタンスの種類

 この「インスタンス(DOSプロンプトのウインドウ)」には
 「通常のインスタンス」と「管理者権限のインスタンス」の2種類があります。

 「通常のインスタンス」では「OS(Windows)にログオンしているユーザ」が
 「DOSプロンプト上でコマンドを発行する人(カレントユーザと言います)」として起動します。

 対して「管理者権限のインスタンス」では「OS(Windows)にログオンしているユーザ」が誰であっても
 「管理者」を「カレントユーザ」として起動します。
 つまり、「ユーザ環境変数」へのアクセスはできません

「ユーザ環境変数」は「OS(Windows)へログオンしたユーザ」のみが「参照可能」です。

 ついでに、「環境変数の種類」の説明の際に先伸ばしにした部分を説明しておきます。

 3. システム環境変数とユーザ環境変数に同じ変数があった場合、
  ユーザ環境変数を優先して参照する。
  (ただし管理者権限でのインスタンスは除く)
  (ただし環境変数PATHを除く)

 システム環境変数とユーザ環境変数に同じ変数があった場合、
 「通常のインスタンス」ではユーザ環境変数を優先して参照しますが
 「管理者権限のインスタンス」ではカレントユーザが管理者であることから
 ユーザ環境変数へのアクセスが禁止されるため、結果として
 システム環境変数を優先して参照される形となります。

じゃあ「インスタンスを新たにする」って具体的にどういう事?

 簡単に言うと、今開いているDOSプロンプトを閉じて、もう一回DOSプロンプトを開くことです。
 論より証拠。
 実践していきましょう。

実践する前に(DOSプロンプトの起動方法)

 「環境変数の設定ダイアログ」の起動方法と同様に、
 「DOSプロンプト」の起動方法(優良)を最初にお伝えします。
 「Windowsキー+Rを押してcmd」より楽、
 というかのちのち使い分けという意味で有用な起動方法だと思います。

 通常のインスタンス(Windowsキー+Rを押してcmd、と一緒)

   1. Windowsキーを押す
   2. cmdと打つ
   3. Enterを打つ

 管理者権限のインスタンス

   1. Windowsキーを押す
   2. cmdと打つ
   3. Ctrl+Shift+Enterを打つ
   4. 「このアプリがデバイスに変更を加えることを許可しますか」ダイアログで「はい」を押す
 
 
 「環境変数の設定ダイアログ」の起動方法と同様に、マウス操作不要です。

環境変数をいじったその後は(実践編)

 1. 「通常のインスタンス」を起動します。

DOSプロンプト(通常のインスタンス)
C:\>

 2. 「環境変数の設定ダイアログ」を起動します。(スクショ割愛)

 3. 「ユーザ環境変数」に以下の変数を新規追加します。(*7)
   あくまで動作確認なので、お好きな値でも構いません。

     変数名 : HOGE
     値   : fugafuga

 4. <1>のDOSプロンプトにて、追加した「ユーザ環境変数」を確認してみましょう。
  環境変数を確認するには「SET」コマンドを使います。

DOSプロンプト(通常のインスタンス)
C:\>SET HOGE
環境変数 HOGE が定義されていません

 5. 「定義されていません」と言われてしまいました。(悲)
 6. このDOSプロンプトを閉じます。
 7. もう一回「通常のインスタンス」を起動します。(インスタンスを新たにする操作)
 8. もう一回「SET」コマンドを打ちます。

DOSプロンプト(通常のインスタンス:再起動後)
C:\>SET HOGE
HOGE=fugafuga

 9. 出てきました!
 10. <2>の「環境変数の設定ダイアログ」で、先ほどの環境変数の値を変更します。

     変数名 : HOGE
     値   : mogumogu

 11. <9>の「DOSプロンプト」で「SET」コマンドを打ちます。

DOSプロンプト(通常のインスタンス:再起動後)
C:\>SET HOGE
HOGE=fugafuga

 12. 案の定変わっていませんね。
 13. DOSプロンプトを再起動して、もう一回「SET」コマンドを打ちます。

DOSプロンプト(通常のインスタンス:更に再起動後)
C:\>SET HOGE
HOGE=mogumogu

 14. 変更が確認できました。
 15. <10>の「環境変数の設定ダイアログ」で先ほどの環境変数の値を削除します。
 16. <14>のDOSプロンプトで「SET」コマンドを打ちます。

DOSプロンプト(通常のインスタンス:更に再起動後)
C:\>SET HOGE
HOGE=mogumogu

 17.消えてないですね。
 18.DOSプロンプトを再起動して「SET」打ちます。

DOSプロンプト(通常のインスタンス:更に更に再起動後)
C:\>SET HOGE
環境変数 HOGE が定義されていません

 19. 削除が確認できました。

実践まとめ

  実践した通り、DOSプロンプトを再起動しない限り、環境変数を正しく読み出せないという結果になりました。
  これは「DOSプロンプトのインスタンスが新しく作成される際に、環境変数がロードされる」というWindows仕様による挙動です。
  ですから、環境変数をいじった際は必ずDOSプロンプトを再起動するようにしましょう。

Windowsバッチとインスタンス

 ここでいうWindowsバッチとは「DOSプロンプト上で実行可能なコマンド」を集めて
 「プログラム」としたもの(.bat)だと思ってください。
 Windowsバッチ(.bat)をダブルクリックで起動すると
 「通常のインスタンス」で各コマンドが実行されます。
 
 Windowsバッチにおいては「バッチが起動してから終了するまで」がインスタンスのライフサイクルです。
 
 例えば「何かしらの環境変数を参照しているバッチ」があったとします。
 バッチが動いて環境変数への参照がうまくいき、バッチが正常終了しました。
 その後に環境変数の値を「環境変数の設定ダイアログ」から変えました。
 もう一回動かすと、「変更後の値」で正しく参照されている事がわかります。

 「環境変数」を扱う際に「DOSプロンプトが最初の一歩」と申し上げた理由の一つがここにあります。

 バッチは起動の都度、良くも悪くもインスタンスが新たにされるため
 「環境変数」が変わったところで「バッチ上で動作確認している限り」は
 「インスタンスを新たにしなくては、変更後の環境変数は読み取れない」というルールを意識する事がありません。

 その後、DOSプロンプト上で「変更後の環境変数」を確認しなくてはいけない時に違和感を覚えるはずです。
 「あれー?変わってないなぁ?」と。

 DOSプロンプトを再起動する癖がないからです。
 私も初学の際は何回かこの沼にハマりました。*8

 ちなみに、Windowsバッチを「管理者権限のインスタンス」で実行したい場合は
 Windowsバッチ自体を「管理者権限で実行すればよい」だけです。
 (右クリック⇒管理者として実行)*9

環境変数「PATH」について

 それでは特殊な環境変数「PATH」について説明します。
 

PATHの参照のされ方

 まずは振り返りから。
 先ほども追加で説明した「環境変数の種類」についてです。

 3. システム環境変数とユーザ環境変数に同じ変数があった場合、
  ユーザ環境変数を優先して参照する。
  (ただし管理者権限でのインスタンスは除く)
  (ただし環境変数PATHを除く)

 何故、「環境変数PATH」が除かれるかというと
 「環境変数PATHだけはどんな時もシステム環境変数PATH+ユーザ環境変数PATHで参照される」からです。

 どういう事かというと、以下の通りです。

 ユーザ環境変数のPATH  :C:\tools;D:\misc\toarutool\bin;
 システム環境変数のPATH :C:\Program Files\aiueo\bin;C:\Programs\kakikukeko\bin;

 ※PATHは上記のように複数のフォルダを指定する事が可能で、「;(セミコロン)」で区切って定義します。
 ※「PATHそのものが何者か?」というのは後ほど説明します。

DOSプロンプト(通常のインスタンス)
C:\>ECHO %PATH%
C:\Program Files\aiueo\bin;C:\Programs\kakikukeko\bin;C:\tools;D:\misc\toarutool\bin;

「ECHO」コマンドは標準出力に文字列を出力するコマンドです。
環境変数にアクセスする際は「%」を使います。上記のように囲って指定します。*10

 「システム環境変数PATH」と「ユーザ環境変数PATH」が結合した文字列
 「PATH」として呼び出されている事がわかります。*13

 「通常のインスタンス」であれば
 「システム環境変数PATH+ユーザ環境変数PATHの文字列」となります。
 「ユーザ環境変数PATH」が未定義であれば、「システム環境変数PATH」のみが参照されます。
 
 「管理者権限のインスタンス」であれば常に「システム環境変数PATH」のみが参照されます。
 

「PATH」って結局なによ?

  「PATHを通す」、「PATHが通っている」。
  よく聞く言葉です。
  これは「カレントディレクトリによらずPATH上のフォルダ配下へのアクセスが可能であること」を指します。

  これこそが特殊な環境変数「PATH」の役割です。
  環境変数PATHに設定されたフォルダは「PATHが通った」状態となり、
  カレントディレクトリがどこであろうが、そのフォルダの下にアクセスが可能です。

DOSプロンプト(通常のインスタンス)

C:\folder1>ECHO %PATH%
C:\misc\abc\bin;
C:\folder1>dir C:\misc\abc\bin
(中略)
2019/01/01  12:34           104,458 gogogo.exe
(中略)
C:\folder1>gogogo.exe
# C:\misc\abc\bin\gogogo.exeを実行する。

  「現在folder1フォルダにいるのにmisc\abc\binフォルダの.exeを叩ける」という事ですね。

PATHの参照順(PATHが示す複数フォルダに同じ名前のexeがあった場合)

  PATHは多数のフォルダが「;(セミコロン)」で区切られた文字列です。

  それでは「システム環境変数PATH」が指し示す一つのフォルダと
  「ユーザ環境変数PATH」が指し示す一つのフォルダに、
  「それぞれ同じ名前のexeファイルがあった場合」はどうなるのでしょう?
  
  答えは「より先頭にあるフォルダ、その配下のexeが優先される」です。

例)
   ユーザ環境変数 「PATH」:C:\Usr\abc\bin;
   システム環境変数「PATH」:C:\System\xyz\bin;C:\toolz\aaaaa;

DOSプロンプト(通常のインスタンス)
#「システム環境変数」と「ユーザ環境変数」での同じexe
C:\>dir C:\Usr\abc\bin
(中略)
2019/01/01  12:34           104,458 yaritai.exe
(中略)
C:\>dir C:\System\xyz\bin
(中略)
2017/10/09  09:58           44,392 yaritai.exe
(中略)
C:\>yaritai.exe
#システム環境変数の「C:\System\xyz\bin\yaritai.exe」が実行されます。
DOSプロンプト(通常のインスタンス)
#「同じPATH」の中での同じexe
C:\>dir C:\toolz\aaaaa
(中略)
2019/01/01  12:34           104,458 dd.exe
(中略)
C:\>dir C:\System\xyz\bin
(中略)
2018/02/15  05:26           20,305 dd.exe
(中略)
C:\>yaritai.exe
#より先頭にある「C:\System\xyz\bin\dd.exe」が実行されます。

  前述の通り「PATH」は「システム環境変数のPATH」と「ユーザ環境変数のPATH(なければ空)」を結合した文字列です。

  例えば「自分のユーザ環境変数にPATHを追加したのに動かない」というのはよく聞く話ですが
  大概「PATHの順番が間違っている(意図せず先頭が優先されてしまっている)」事が原因です。

  身も蓋もない言い方をすれば「システム環境変数のPATHの先頭にあれば動く」なのですが
  「システム環境変数のPATH」をいじってしまうと
  その端末にログオンする可能性のあるユーザ全員が影響をうけるため
  安易な修正はおすすめしません

  どうしようもない時は「その端末にログオンする可能性のあるユーザ全員」に確認を取った上で
  「システム環境変数のPATH」の先頭に「追加したい対象のフォルダ」を置きましょう。
  大概、これで治ります。
  ただ、しつこいようですが安易な修正はダメです。
  「こっちは動くようになったが、あっちは動かなくなった」というのも往々にしてあり得るからです。

実行プログラムが「実行できる状態」とは?

 DOSプロンプトから「プログラム」を実行する場合、
 つまり、

DOSプロンプト
C:\dokoka>nanika.exe

といった形でプログラムを実行する場合、
OS(Windows)は「そのプログラムが実行できるかどうか?」という判定を
環境変数「PATH」だけを基準にするのではなく以下の優先順位で行っています。

 1. カレントディレクトリ
  ⇒直下にそのプログラムがあるかどうか。
 2. 環境変数「PATH」
  ⇒PATHの優先順位に従って前方から走査。
 3. HKLMレジストリ
 (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths)
  ⇒ここに定義されているかどうか。*11

環境変数を一時的に変更したい

 「一時的な環境変数」の制御には
 これまでも何度か登場している「SET」コマンドを使います。 
 非常によく使われるコマンドと言って差し支えないと思います。

 まずは基本説明をしていきましょう。
 ヘルプを見てみます。

DOSプロンプト
C:\>SET /?
cmd.exe 環境変数を表示、設定、または削除します。

SET [変数名=[文字列]]
(中略)

ヘルプの文言とは若干異なりますが、コマンドの様式ベースで言うとこんな感じです。
使い道は大きく3つ。

 1. 引数なし        【表示】

DOSプロンプト
C:\>SET
ARE=xxx
KORE=yyyy
SORE=zzzzz
・
・
・
#アクセス可能な全ての環境変数が表示されます。

 2. 文字列を指定      【検索】

DOSプロンプト
C:\>SET A
AA=aa
ABC=abc
Aitsu=soitsu
・
・
#「A」から始まる環境変数を全て表示します。

C:\>SET BCD
BCD=bcd
BCDE=bcde
BCDEF=bcdef
・
・
#「BCD」から始まる環境変数を全て表示します。

 3. 「変数名=値」の形で指定 【設定】

DOSプロンプト
C:\>SET HOGE=fugafuga
#環境変数「HOGE」に「fugafuga」をセットします。
#「SET」するときに「%」は不要です。
#「=」の前後に「半角スペースはない」事に注意してください。
C:\>ECHO %HOGE%
fugafuga

 ではお題目どおり「環境変数を一時的に変更したい場合」について説明していきます。
 上記「3」の通り「変数名=値」の形で「SET」コマンドを実行します。

 ですが、ちょっと待ってください。
 ここでいくつか疑問があります。

 1. 「SET」コマンドで設定されるのは「環境変数」って言っているけど、
   それは「システム環境変数」なの?それとも「ユーザ環境変数」なの?
  (つーかヘルプに表示されている「cmd.exe 環境変数」って何よ?)

 2. 一時的って「いつからいつまで?」

 なるほど。ごもっともです。
 それでは順に回答します。

 cmd.exe環境変数

  「SET」コマンドで「設定」されるのは
  「システム環境変数」でも「ユーザ環境変数」でもありません

  ヘルプに表示されている通り「cmd.exe環境変数」が「SETコマンド」で操作される対象となります。

  それだけではありません。
  「SET」コマンドの「引数なし」や「文字列指定」の実行にて
  「表示」や「検索」の対象となるのも「cmd.exe環境変数」です

 また新しい変数の種類ですか?(ゲンナリ)

  いえいえ、単純な「テンポラリー領域」です。
  実践編のまとめで「DOSプロンプトのインスタンスが新しく作成される際に環境変数がロードされる」と申し上げましたが
  その「ロードされる先の場所(作業領域)」とご認識ください。

環境変数の設定ダイアログ

   ↓  設定

環境変数(システム環境変数+ユーザ環境変数)

   ↓  ロード

DOSプロンプトのインスタンス

   ↓  生成

cmd.exe環境変数

   ↑  アクセス

SETコマンド

  「上図」の通り、「SET」コマンドの操作対象と「環境変数の設定ダイアログ」の操作対象は異なります

  また「cmd.exe環境変数」では、どれが「システム環境変数」だとか「ユーザ環境変数」だとかではなく
  「環境変数の振る舞い」に従って「一意」に展開されます。

  おさらいです。

 1. システム環境変数としてのみ宣言している変数は管理者権限がなくてもアクセスが可能。
 2. システム環境変数とユーザ環境変数には同じ変数を指定できる。
 3. システム環境変数とユーザ環境変数に同じ変数があった場合、
   ユーザ環境変数を優先して参照する。
  (ただし管理者権限でのインスタンスは除く)
  (ただし環境変数PATHを除く)

  つまりこの振る舞いはDOSプロンプトの「インスタンス」が生成された際に
  「cmd.exe環境変数」がどのように一意に決定されるか?もまた示しています。

 cmd.exe環境変数のライフサイクル(「一時的」という言葉が示す範囲)

  「上図」がそのまま答えですが、「cmd.exe環境変数」は「インスタンス」に依存していますので
  cmd.exe環境変数のライフサイクルは「インスタンス」のライフサイクルと同じです。

  つまり、DOSプロンプトであれば「開いてから閉じるまで」、
  「Windowsバッチ」であれば「実行から終了まで」、となります。

 あらためて「SET」コマンドを実践

  それでは以下の条件の元、「SET」コマンドを実行していきましょう。

  <ユーザ環境変数>
    CITY : 八王子市
 
  <システム環境変数>
    PREFECTURE : 東京都

 通常のインスタンスでの「SET」
DOSプロンプト(通常のインスタンス)
# まずは「cmd.exe環境変数」としてロードされた
# システム環境変数「PREFECTURE」とユーザ環境変数「CITY」を確認しましょう。
C:\>ECHO %PREFECTURE%%CITY%
東京都八王子市
# では「PREFECTURE」を「神奈川県」に、「CITY」を「横浜市」にします。
C:\>SET PREFECTURE=神奈川県
C:\>SET CITY=横浜市
C:\>ECHO %PREFECTURE%%CITY%
神奈川県横浜市
# 「cmd.exe」環境変数に対して環境変数「WARD」(鶴見区)を追加します。
C:\>SET WARD=鶴見区
C:\>ECHO %PREFECTURE%%CITY%%WARD%
神奈川県横浜市鶴見区
# ここでインスタンスを再起動します。
DOSプロンプト(通常のインスタンス:再起動後)
# さっきと同様に「PREFECTURE」「CITY」を確認しましょう。
C:\>ECHO %PREFECTURE%%CITY%
東京都八王子市
# 追加した「WARD」を確認しましょう
C:\>SET WARD
環境変数 WARD が定義されていません
C:\>ECHO %WARD%
%WARD%

  おわかりいただけましたでしょうか?

  「SET」コマンドを使って「PREFECTURE」を「東京都」から「神奈川」へ変更したり
  「WARD」という環境変数を追加したりしましたが
  インスタンスを再起動すると、その変更がなかったことになっています。

  この通り、「SET」コマンドは「システム環境変数」や「ユーザ環境変数」に対して直接操作するのではなく
  「cmd.exe環境変数」に対して操作をしているため、
  「システム環境変数」や「ユーザ環境変数」の値に影響を及ぼしません

  一応、管理者権限のインスタンスも見ておきましょう。

 管理者権限のインスタンスでの「SET」
DOSプロンプト(管理者権限のインスタンス)
# 通常のインスタンスと同様に
# システム環境変数「PREFECTURE」とユーザ環境変数「CITY」を確認してみましょう。
C:\>ECHO %PREFECTURE%%CITY%
東京都%CITY%
# そうですね。
# 「CITY」はユーザ環境変数ですから、「cmd.exe環境変数」にもロードされていませんね。
# では「CITY」に「日野市」を追加しましょう。
C:\>SET CITY=日野市
C:\>ECHO %PREFECTURE%%CITY%
東京都日野市
# ではまたインスタンスを再起動しましょう。
DOSプロンプト(管理者権限のインスタンス:再起動後)
C:\>ECHO %PREFECTURE%%CITY%
東京都%CITY%

  同じですね。

「SET」コマンドで環境変数「PATH」を編集する。

  環境変数「PATH」への「SET」も同様です。
  よくあるパターンでご紹介します。

DOSプロンプト(通常のインスタンス)
# 「PATH」の先頭に追加する
#   「どうしても新しいパスを優先して設定したい」場合です。
#   「環境変数PATH」で説明した通りですが、
#   「より後ろに設定されているPATH」を読み込めなくなるリスクがあります。
C:\>SET PATH=C:\atarasii\bin;%PATH%

# 「PATH」の末尾に追加する
#   「既存のPATHを保持しつつ、一番後ろに設定を追加する場合」です。
#   「先頭に追加する」パターンと逆のリスクですが、
#   追加したフォルダの優先順位は一番最後なのでそこだけ注意してください。
C:\>SET PATH=%PATH%C:\ushiro\bin;

# 「PATH」を上書きしてしまう
#   「既存のPATHは全無視して、このインスタンスでだけPATHを制限する場合」です。
#   一部、既存のPATH環境変数の値を使用したい場合は
#   上書きする内容としてあらためて設定する必要があります。
C:\>SET PATH=C:\konotoki\bin;C:\dake\bin;C:\dakara\bin;

# オリジナルの「PATH」と新たな「PATH」を別々に同居させる
#   どうしても「PATH」という役割を2つ以上与えたい場合は、
#   変数を別に用意する方が望ましいと思います。
#   「PATHの優先順位」を掌握しているのであれば前3つのやり方でも全然構いませんが・・・
C:\>SET PATH_EX=C:\konotoki\bin;C:\dake\bin;C:\dakara\bin;
C:\>ECHO %PATH%
#「環境変数の設定ダイアログ」で設定された「環境変数PATH(語義そのまま)」を出力
C:\>ECHO %PATH_EX%
#自分で用意したオリジナルの「PATH」(的なもの)を出力

「SET」コマンドで環境変数を削除する。

  「SET」コマンドで「cmd.exe環境変数」の削除も行えます。*12

DOSプロンプト
C:\>SET HOGE=fugafuga
C:\>SET HOGE
fugafuga
# 削除では「SET HOGE=」とだけ打ちます。「=」の後にスペースなどは要りません。
C:\>SET HOGE=
C:\>SET HOGE
環境変数 HOGE が定義されていません

環境変数の設定に「SETX」コマンドを使ってはいけない理由

 「SET」とは別に「SETX」というコマンドが存在します。
 これは「cmd.exe環境変数」ではなく「システム環境変数」や「ユーザ環境変数」を
 ダイレクトに変更するコマンドです。

 はっきり言って個人的にはおすすめしません
 おすすめしない理由は別記事にまとめていますので
 良かったらご参照ください。

まとめ

 新しい言語やフレームワークをインストールした後に
 脊髄反射で「システム環境変数PATH」の頭にbinフォルダを追加したり、
 Windowsバッチを適当に組んで「SET」を何となくで使ってみたり、
 という方は意外と多いのではないでしょうか?
 (かくいう私もその口でした)

 ここまで出てきた「インスタンス」や「cmd.exe環境変数」といった定義は
 耳慣れない概念ではありますがこれらを理解することによって、
 「環境変数に何が起きているのかわからない」という事はなくなると思います。

 元々は「環境変数」の「か」の字も知らない方向けに書いた記事ですので
 「イメージ付け」+「おおまかな概念の共有」を目的としています。

 それでも「こうした方が理解が早まるんじゃない?」とか
 「厳密な理論は全然違うよ!」といったご意見・ご指摘がございましたら
 遠慮なくコメントにお寄せ頂ければと思います。
 
 閲覧頂きありがとうございました。
 

(Appendix) 「DOSコマンド」の大文字・小文字について

 「DOSプロンプト」の「コマンドを解釈してOSへ命令する機能(インタプリタと言います)」は
 実は、大文字・小文字を基本的に意識しません

 ただし、「SET」コマンドの引数は「変数名」「値」なので
 大文字・小文字を意識します
 

DOSプロンプト
# 本稿でよく出てきたコマンドたち
C:\>SET HOGE=fugafuga
C:\>SET HOGE
HOGE=fugafuga
C:\>ECHO %HOGE%
fugafuga

# 実は小文字でもOK
C:\>set hoge
HOGE=fugafuga
C:\>echo %hoge%
fugafuga

# ただしSETコマンドの引数は「変数名」「値」なので
# 大文字小文字が意識されて設定される。
C:\>set moge=MOGUMOGU
C:\>set moge
moge=MOGUMOGU
# 逆に小文字の環境変数を大文字で引いてみる。これもOK。
C:\>set MOGE
moge=MOGUMOGU
C:\>echo %MOGE%
MOGUMOGU

  本稿では、書き味を揃える意味で「DOSコマンド」は全て大文字で記載しています。
  
  これら大文字・小文字については殊更の言及はしませんが
  コマンドに慣れるまでは、標準の「ヘルプ(/?)」の記載に合わせた方が
  変なクセも付かないので、よいかとは思います。
 
 
以上。
―――――――――――――――――――――――――
 

脚注

 「戻る」リンクで何となくの所へ戻ります。

1

「定数」と書くと、いや「値」を変えられるじゃん?とか、
そもそも「immutable」の概念などへも話が発散しそうなので
あえて「変数」にしました。
であれば、文字列値がimmutableのPythonコードなんか挙げるなよ、と・・・
戻る

2

「バグ」だからといって、それが「障害」と認知されるかどうかは別の問題です。
「住所」が「40歳」のイカれた空間(固有結界)もこの世にはたくさん存在するわけで・・・。
よーし、落ち着いて・・・まずはゆっくり深呼吸をするんだ・・・。
戻る

3

無論、変数のライフサイクルとしてそのスコープが極小であれば
ループ制御文で見る「int i=0」のような記述は許容しますし、
「tmp」などの「汎用的に見える、あいまいな文字列を絶対に使うな」
という事を言いたいわけではありません。

「住所」と「歳」のように名実があからさまに矛盾した「変数」
どう考えてもメリットがないので避けるべき、という事を言いたいわけです。
戻る

4

何度も「環境変数の設定ダイアログ」の起動を実行していると
「Windowsキー+I(アイ)」でなくても
「Windowsキーを押す」+「kan(半角英字)と打つ」
程度で「環境変数の編集」がサジェストされるようになる場合もあります。

なお、「何回以上やればサジェストされるか?」などの条件は不明です。
私のメイン環境ではいつの間にか出ていました。

そんなサジェストをそこまで当てにするのもどうかと思ったので
手順のぶれようがない「Windowsキー+I(アイ)」からの「環境と打つ」を最優良と判断しました。

また、優良手順を模索するまでの筆者の紆余曲折を蛇足ながら補足します。
本当に蛇足ですので「優良」の経緯を知りたい方のみどうぞ。
戻る

「環境変数の設定ダイアログ」起動方法の模索 ~紆余曲折~

Windows10では、Windowsメニューやコントロールパネルの「見え方」が
バージョンやプロファイル(ポリシーもあるかな?)によってまちまちです。

それに気づいたのはWindows10を初めて触った時でしたが
既にそのときはWindows10が発売されてからだいぶ経ったあとで
「ん?Windows7のあの機能どこいった?」とか「こんな機能ないかな?」ってんで
Windowsの設定画面をひとつ触るにも脊髄反射でGoogle先生に聞いてみたりしていたわけなんですが
説明してくれるサイトをいくつか見てみると
説明図であるところのスクショ内にていわゆるコントロールパネルやWindowsの設定における
「ダイアログの見栄え」がサイトごとに異なる事に気付きました。
「環境変数の設定ダイアログへの導線」も然り、です。

最初はあまり気にしなかったのですが
いちいちサイトで調べるのも面倒だなと思っていました。
調べるたびに「サイト」も「手順」も違うし…。ブックマークしろよ。

まぁ従来、私は「Windowsキー+Pause」で「システム」画面を開いてから
システムの詳細設定リンク」をクリックして「システムのプロパティ」を開き
さらに「詳細設定」タブから「環境変数ボタン」を押して
「環境変数の設定ダイアログ」を出す派でした。
今思えばだいぶ手間ですが…環境変数なんかそんな触らないし…(震え声)

だから「環境変数の設定ダイアログ」を出すのにも特段困ってはいなかったのですが
昨今のセキュリティ事情に伴い
端末自身のセキュリティに対する現場の締め付けも厳しくなってきました。
具体的には、私のところでは個人端末から「管理者権限」を取り上げられてしまいました。

「システム」画面内の「システムの詳細設定リンク」をクリックするのには
「管理者権限」が必要であることから
従来の「環境変数」を開く導線であった「システムのプロパティ」が
結果として、開けなくなってしまいました。

もちろん「環境変数ダイアログ」を開く方法は上記の通り色々なサイトで言及されていて、
ただただコントロールパネルを辿っていきゃあいいだけなのですが
サイトによってまちまちな手順を自分の中では固めたいな、と。

あと、マウス操作があまり好きではない(社二病)ので
できればキーボード操作だけで「環境変数」ダイアログを出せないものか、と。

更に、私はもう「システム環境変数」を現場ではいじれなくなってしまいましたが
手順的に「ユーザ環境変数の設定」と「システム環境変数の設定」を
簡単にディスパッチできるような操作であれば
他の人向けとしても汎用的な手順として展開できるな、と思いました。

そこで編み出されたのが当手順です。

別に目新しい内容でもないですし、
むしろ他サイトでもバンバン記載されている垢まみれの情報ではあるのですが
個人的なニーズにマッチするだけでなく
同じように管理者権限を取り上げられてブルーになっている人も
中にはいるんじゃないかなと思ってのご提示でした。

以上です(長い)
戻る

5

Windowsメニューも「コマンドプロンプト」という表記ですし
私自身も「コマンドプロンプト」と呼ぶ事のほうが多いですが
「コマンドプロンプト」は元々「コマンドを促すもの」という広義な単語です。
という事もあって、あえて本稿では「DOS(コマンドの)プロンプト」という記載を採用しています。

「コマンドプロンプト?え?なんのコマンドのプロンプト?意味が広すぎて草。」
と宣う方はまずいないとは思いますが一応、原義について補足させて頂きました。
戻る

6

「DOSプロンプトを起動するcmd」と「DOSプロンプト内で打つcmd」とでは
挙動が異なるので、良い説明ではないというのは自覚しています。
何故なら、既に起動しているDOSプロンプト上でcmdと打っても環境変数はリロードされないからです。
つーか、環境変数をリロードするコマンドをよこせって話です。(論点ずらし)
戻る

7

 変数名 : HOGE
 値   : fugafuga

大丈夫です。
変数名はちゃんと「意識」してつけています。
テストコードなんて何でもよいのです。
だって、「HOGE」のライフサイクルは、
理解を促す為だけに作ったサンプル内に限られているでしょう?(詭弁)

「変数の名実一体」は「システム運用の必要性に駆られてソースコードを参照する人の為の概念」です。

システムを運用するに当たって
「100%人に見られる事のないソースコード」が現実的ではないのであれば
初めから「人に見られた時のこと」を想定するべきですよね?
悲しいかな、「現場で扱うソースコードの参照可否は作った人間が決めるものではない」のです。
戻る

8

というか、DOSプロンプトどころか昔はとにかくPCを再起動していた気がする。
いい時代になったものじゃよ…

逆に、「沼にハマった」とか言っていますが
「苦労がなかったら覚えない(=苦労したから覚えられた)」とは自分でも思います。
同時に、昔の人と同じレベルの「苦労」を「昨今の若者」が
全部を全部なぞる必要はないと思っています。

「昨今の若者」はとかく「楽をしたい」とか「頭が弱い」とかいう風に見られがちですが
実は「目先の苦労や失敗を極端に忌避している」だけです。

「苦労したらいいことあるよ」とか「失敗しても死なないよ」とか
ひいては「頭をつかうことの個人的な(≠会社的な)メリット」などなど
「教えてくれる上の人」が昔に比べて少なくなったからでしょうね。
ただただ「やらされてる感」が強い、というか。

まぁ「昔のように苦労しなくて全然よい」という事では決してなくて
先人たちのおかげで楽になった部分を踏まえて、自分がどう振る舞うかはちゃんと自分の考えを持てよ?
という事は言いたいですね。

「デキていない奴が多すぎる!けしからん!」ということではないです。
何故なら、「デキていない奴の絶対数」と「デキる奴の偏差値」が極端過ぎるが故に
「デキる奴」は、本人のアピール如何を問わず、とにかく目立つし、評価されやすいし(されているし)。
とどのつまり、この巨大な「デキない奴が多すぎるインフラ」の中で
「デキる奴が貧乏くじを引くような胸糞展開」は
昔に比べたら全然、起こりにくいんじゃないかなとの所感です。
それだけで何か救われるというか、ほっこりするというか。

現場では慢性的に「人がいない」「人がいない」言うてますけど
「買い手」は「デキる奴」を探しているのに
「デキない奴」だけがショーケースに並んでいて
「デキる奴」は売り切れ、というただそれだけのこと。
これが今の「売り手市場」の実態かなぁとも思います。
詮無い話ですがね。

あれ…何の話だっけ?
戻る

9

将来的に、バッチファイルをCtrl+Shift+Enterで叩いたら「管理者権限で実行」にならないかなぁ…
ただ「sudo」的な操作に対して
アクセシビリティというか「手間」を下手に下げてしまうと
セキュリティが…って事なんですかね。
世知辛いねぇ。
もう万人に使わせなければいいんじゃないの?(暴論)
戻る

10

Q.「SET」コマンドの時は「%」なんてつけてなかったじゃん!
A.本文中の説明(後述)とも重複しますが、「SET」コマンドに第一引数だけ与えて実行すると、そのプレフィックスに従った環境変数が全て表示されます。

DOSプロンプト
C:\>SET T
TEMP=C:\Users\user\AppData\Local\Temp
TMP=C:\Users\user\AppData\Local\Temp

みたいな。
なので「環境変数」ではなく「ただの検索文字列」を
「SET」コマンドの第一引数に指定しているだけです。
単体で環境変数にアクセスする際は「%」で囲う必要があります
戻る

11

「SnippingTool」や時には「chrome」など
意外なアプリが定義されていたりするので暇な方は確認してみるとよいです。
何に役立つかって、そりゃ「Windows+R」で起動できる事ですよ。
戻る

12

「SET」コマンドで「cmd.exe環境変数」の削除も行えます…が
ただ、そもそも「SETでの削除」が必要な時ってそんなにあるのかなぁとは個人的に思います。

「これ以上、このcmd.exe環境変数を参照させたくない」という事情は
そもそもの「変数のスコープ設計(=変数のライフサイクル設計)」の良し悪しでしかなくて
「未定義(削除された状態)」をあらたに再設定して、値を参照・判定したりするくらいであれば、
変数を分けて「値ありき」で扱ったほうが望ましいかと。

プログラム上「インスタンスのライフサイクルが鬼のように長い」といったケースでは
「予期せぬ参照」を防ぐために有用な場合もあるかもしれませんが
小規模なツールを組む程度の普段使いであれば多用は避けるべきだと思います。
戻る
 

13  

「システム環境変数PATH」と「ユーザ環境変数PATH」が結合した文字列と聞いて
え?たくさんあったらどうすんの?それとも無限に入るの?と思った方は勘の良い方です。

実は、「環境変数」の「変数名」「変数値」には入力できる桁数に制限があります。
この入力制限は「PATH」のみならず全ての環境変数に対するルールです。

変数名 : 259バイトまで入力可能
変数値 : 2,047バイトまで入力可能

259ってなんだ?255じゃないのか。
まぁいいか。
試しに限界値を入れてみるか。

DOSプロンプト(通常のインスタンス)
C:\>SET 1
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789=12345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567890
1234567890123456789012345678901234567890123456789012345678901234567

狂気を感じる

ちなみに「PATH」については
ユーザ環境変数「PATH」、システム環境変数「PATH」、それぞれ2,047バイトです。
フォルダを2つ以上含む場合はセパレータの「;(セミコロン)」を含みます。

また最後の要素の「;(セミコロン)」を除いて「2,047」バイトです。(ややこしい)

要はまとめると、「PATH」の入力桁数の限界値は
「セミコロン(末尾含む)」と「フォルダ構成文字列」と全て合わせて2,048バイト
です。

DOSプロンプト(管理者権限のインスタンス)
C:\Windows\System32>ECHO %PATH%
C:\aaaa\bin;C:\bbbb\bin;C:\ccc\bin;………(中略)………C:\zzzz\bin;
# 「末尾のセミコロン」を足して、MAX2,048バイト。

つまり「cmd.exe環境変数」として扱える「PATH」の桁数としては
4,096バイトがMAXとなります。

DOSプロンプト(通常のインスタンス)
C:\Users\user>ECHO %PATH%
C:\aaaa\bin;C:\bbbb\bin;………(中略)………C:\zzzz\bin;C:\u1\bin;C:\u2\bin;
#「;(セミコロン)」まで含めると
# システム環境変数の2,048バイトと
# ユーザ環境変数の2,048バイトを足して
# MAXは4,096バイトとなる。

まぁ、昔は変数値が1024だか2047だか、2047を拡張できるパッチがあるだのなんだのと
色々とあったそうですが、
ぶっちゃけ環境変数の入力桁数制限の重要性という側面についてはすいません、
寡聞にして存じ上げません。

本稿で説明しようとも考えたのですが
そんな桁が溢れちゃうようなパターンはそうそうない(=基本ではないよなぁ)
と判断し、ただ全部割愛もアレだと思ったので
脚注の補足としてまとめさせて頂きました。
ご了承ください。
戻る 

206
231
11

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
206
231