1.【概要】
タイトルを見て「何をいまさらw」と思われた方も多いと思います。
確かに、Windows / UNIXともに PATH
環境変数の設定方法はいろんな場所で紹介されています。
その多くは Windows の場合は ;
で、Linux などの UNIX 系 OS では :
でディレクトリパス名を区切って PATH
環境変数に設定する、というものです。
しかし、それらを読んでいて、私はふと疑問に思ったわけです。
「あれ?ディレクトリパス名そのものに':'
なり';'
が含まれていた場合はどうすればいいの?」
そんな状況はレアケースだとは思うのですが、気になってしまったものは仕方ありません。
この記事ではその疑問に関する調査結果について述べています。
お暇でしたらお付き合いください。
2. 【対象環境】
以下の OS について調査を行いました。
- Windows 10
- Linux (Ubuntu 20.04.6 LTS, Linux on Windows)
3. 【問題点のおさらい】
例えば Linux をはじめ、UNIX 系 OS の場合の PATH 環境変数は通常以下のように書きます。
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ここに、~/bin:1
というディレクトリパス名を追加したいとして、ストレートに以下のように書いたとします。
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:~/bin:1
さて、問題です。~/bin:1
の配下にある実行可能ファイルは検索対象として認識されるでしょうか?
実験してみたところ、認識されませんでした。まぁ、:
が区切り文字である以上は最後の ~/bin
と 1
は分割されて認識されるはずなので、当然の結果ではあります。
Windows でも区切り文字が;
であるだけで同じような問題が発生し得ます。
では、~/bin:1
のような区切り文字を含むディレクトリパス名を実行可能ファイルの検索対象ディレクトリパス名として正しく認識させるためにはどのように PATH
環境変数に設定すればいいのでしょうか?
また、そういった PATH
環境変数を解析するためには単に区切り文字でぶった切るだけでいいのでしょうか?
このような疑問について、Windows と Linux 上で調べてみました。
3. 【Windows の場合】
他のバージョンではどうなのかわかりませんが、少なくとも Windows 10 には PATH
環境変数を編集する GUI があるので、まずはその GUI の振る舞いを調べてみました。
Windows 10 の場合、システム⇒システムの詳細設定⇒環境変数 の手順で画面を開くと、環境変数の編集画面が開きます。
ここで、PATH
環境変数を選び「編集」を押してPATH
環境変数の値を編集する画面に移動します。
新たにパス名を追加するために「新規」を押して、適当なディレクトリパス名 C:\TEMP;1
を入力し、「OK」を押していったん PATH
環境変数の編集を終了します。
次に、再び PATH
環境変数を選んで「編集」を押して更に「テキストの編集」を押します。さて、PATH
環境変数にはどのように反映されているでしょうか?
このように C:\TEMP;1
がダブルクォート "
でくくられて PATH
環境変数に追加されていました。
では、本当にこれで C:\TEMP;1
の配下にあるファイルにもPATH
が通るのでしょうか。
実験のためにコマンドプロンプトから以下のように入力してみました。
C:\>mkdir "C:\temp;1"
C:\>set PATH=%PATH%;"C:\temp;1"
C:\>echo @echo off > "C:\temp;1\hello.bat"
C:\>echo echo hello world. >> "C:\temp;1\hello.bat"
C:\>hello
hello world.
C:\temp;1\hello.bat
がちゃんと実行されて hello world.
のテキストがコンソールに表示されたので、一応この方法で行けるようです。
逆に、PATH
環境変数を自力で解析する場合は、"
でくくられている範囲内の;
はパス名の一部とみなす必要がありそうですね。Windows ではパス名自体に"
を含めることはできないので、"
を何らかの方法でエスケープする方法とかは考慮しなくてよさそうです。
じゃあ "
でくくれば問題解決なのか、というと全く問題がないわけでもないようです。
例えば、where
コマンドでhello.bat
の場所の捜索を試みると、以下のような結果になります。
C:\>where hello
INFO: Could not find files for the given pattern(s).
C:\temp;1\hello.bat
が where
コマンドでの検索には引っ掛かりません。
;
を含まない他のディレクトリにあるバッチファイルは where
コマンドで見つかるので、単にwhere
コマンドが PATH
環境変数の値に含まれている "
を認識せず単に ;
で分割しているかか何かだと思います。
きっとwhere
コマンドのバグなんでしょうねぇ…そしてきっと修正はされないんでしょうね。Windowsだし。
4. 【Linux の場合】
Linux では PATH
環境変数の区切り文字は :
です。その一方、:
を含むディレクトリパスも作れてしまいます。では Linux の場合はどのように対処すればいいのでしょうか?
この調査のために Linux カーネルのソースコードまで調べる羽目になったのですが、結論から言うと Linux では PATH
環境変数からディレクトリパス名のリストを取得する際に環境変数の値を ':' で分割する以外のことは全くしていません。
which
コマンドが実はシェルスクリプトで実装されていた(!!)ので、/usr/bin/which
をテキスト表示してみるとわかりやすいと思います。やっていることは、区切り文字を指定する変数 IFS
の値を :
に設定して PATH
環境変数の値に対して for
文で回しているだけです。
そういう訳なので、Linuxでの PATH
環境変数の扱いについては広く知られている方法が正解のようです。つまり、PATH
環境変数にディレクトリパス名を追加する場合は単に :
で区切ってパス名を設定し、逆に自力で PATH
環境変数を解析する場合は単に :
で分割する、という方法です。
そして、それはつまりLinux では :
を含む名前のディレクトリを実行ファイルの検索パスとして認識させる手段がないことを意味します。
5. 【まとめ】
-
Windows の場合
-
;
を含むディレクトリパス名をPATH
環境変数に設定する場合は"
で囲む。 (例:set PATH=%PATH%;"C:\temp;1"
) -
PATH
環境変数を自力で解析する場合、基本的には;
で分割するが、"
で囲まれた内部にある;
をパス名の一部として解釈しなければならない。 -
PATH
環境変数に;
を含んだディレクトリパス名が含まれている場合、一部のプログラム (where
コマンドなど) が正常に動作しない。
-
-
Linux の場合
-
PATH
環境変数の設定/解析方法は、広く知られている通り、設定時はディレクトリパス名を:
で区切り、解析時は環境変数値を単に:
で分割するだけである。 -
:
を含むディレクトリを実行可能ファイルのパス名としてPATH
環境変数に追加する手段は存在しない。(単に追加することはできるが正しく認識されない)
-