Edited at

「PATH を通す」の意味をできるだけわかりやすく説明する試み

More than 1 year has passed since last update.

「PATH を通す」の意味をできるだけわかりやすく説明する試みです。


前提知識


  • Windows

  • ファイル、フォルダ、フルパス、実行ファイルの意味がわかっている

  • コマンドプロンプト上で実行ファイルを開く程度の操作を行ったことがある


「PATH を通す」とは

特定のプログラムを「プログラム名だけで実行できるようにする」こと。

もっと言うと、プログラム名だけで実行できるようにするために、PATH という環境変数(設定の一種)に「このプログラムも名前だけで実行できるようにしてください」という値を追加すること。


「プログラム名だけで実行する」とは?

プログラムは本来なら「フルパス」を指定しないと実行できない。

たとえば「メモ帳」は C:\Windows\System32\notepad.exe というフルパスなので、メモ帳を開きたい時は「 C:\Windows\System32\notepad.exe を実行してください」と Windows に頼まなきゃいけない。

そうすると Windows さんは「C: ドライブ、の中にある Windows フォルダ、の中にある System32 フォルダ、の中にある notepad.exe というファイルを実行すればいいんだな?」と解釈して、実行してくれる。

でもメモ帳を実行したい時に、いちいち C:\Windows\System32\notepad.exe と書くのはだるすぎる。そこでメモ帳に関して PATH を通してあげると notepad.exe と指定するだけでメモ帳が開けるようになる。PATH を通したおかげで C:\Windows\System32 の部分が自動的に補われるのだ。


PATH の仕組みはどうなっているの?

PATH は結局のところ「フォルダのフルパス」の集まり(を格納した設定)でしかない。

まず中身は以下のようになっている。

C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;....

読みづらいが、わかりやすく書くとこうなる。


  • PATH の中身


    • C:\Windows\system32

    • C:\Windows

    • C:\Windows\System32\Wbem

    • C:\Windows\System32\WindowsPowerShell\v1.0

    • ...



続いてこの PATH がどう使われるかだが、Windows は、与えられたプログラム名を開く時に、以下のようなロジックで開いている。たとえば notepad.exe を与えたとすると、



  • C:\Windows\system32\notepad.exe が存在するか調べる、存在するならそれを開いておしまい

  • 存在しないなら、


  • C:\Windows\notepad.exe が存在するか調べる、存在するならそれを開いておしまい

  • 存在しないなら、


  • C:\Windows\System32\Wbem\notepad.exe が存在するか調べる、存在するならそれを開いておしまい

  • 存在しないなら、


  • C:\Windows\System32\WindowsPowerShell\v1.0\notepad.exe が存在するか調べる、存在するならそれを開いておしまい

  • 存在しないなら、

  • ...

こんな感じで、PATH に入ってるフォルダパスを一つずつ補って開けるかどうかを試していく。


PATH を通す方法

では、その PATH を通すという作業、つまりは「指定したフォルダを PATH という設定に追加する」には、一体どんな方法を行えばいいのだろう。

拙筆だが Windows で環境変数 PATH をいじる方法のまとめ - Qiita にてまとめている。ここでも簡単にまとめておくと、


  • コントロールパネルから行う

  • コマンドプロンプト上で set コマンドを使って行う

以上の二通りがある。具体的な手順は割愛するが、とにかく上記のやり方で追加できる。


どの位置に追加する?

PATH を通す際、どの部分に追加するかという問題がある。たとえば C:\mytool フォルダを通したい場合、以下の候補がある。



  • C:\mytool ★1 最初に入れる?

  • C:\Windows\System32

  • C:\Windows


  • C:\mytool ★2 この辺に入れる?

  • C:\Windows\System32\Wbem

  • C:\Windows\System32\WindowsPowerShell\v1.0

  • ...


  • C:\mytool ★3 最後に入れる?

結論を言うと、別にどこでも良い。

ただし追加した位置によっては問題となるケースがある。次で詳しく。


追加位置が問題となるケース

フォルダパスは PATH のどの位置に追加してもよいが、追加位置によっては問題が起こるケースがある。それが 「PATH を通すことで実行できるようになるプログラム名」が 被った 時だ。

これについても例をあげよう。

たとえば、普通のメモ帳( C:\Windows\System32\notepad.exe )の代わりに、もっと使いやすい改造版メモ帳( C:\mytools\notepad.exe )を使っているとして、この改造版メモ帳を PATH に通したいとする。追加位置として ★1 先頭に追加してみよう。



  • C:\mytool ★ここに追加した

  • C:\Windows\System32

  • C:\Windows

  • C:\Windows\System32\Wbem

  • ...

これで notepad.exe と書くだけで C:\mytool\notepad.exe が実行されるようになる。めでたしめでたし。……いや普通のメモ帳が開けないじゃん。普通のメモ帳もたまに使うんですよねぇ。じゃあこうしようか。


  • C:\Windows\System32

  • C:\Windows

  • C:\Windows\System32\Wbem

  • ...


  • C:\mytool ★こっちに追加してみる?

これでどう?……残念、そうすると notepad.exeC:\Windows\System32\notepad.exe を表しちゃうので、今度は改造版メモ帳が開けません。

以上は極端な例だが、ここで意識しておきたいのは プログラム名が被った場合、一つを除いた、残り全てのプログラム名は隠蔽される(プログラム名だけでは開けなくなる) ということだ。


特定のプログラム名が PATH に通ってるかどうかを調べる

PATH 絡みのトラブルシューティングとして「このプログラム名が PATH に通ってるかどうか調べたい」ことがある。そんなことできるのか。

できる。where という便利なコマンドがある。たとえばメモ帳 notepad.exe について調べてみると、以下のようになる。

$ where notepad.exe

C:\Windows\System32\notepad.exe
C:\Windows\notepad.exe

採用されるのは一番上なので、この場合、notepad.exeC:\Windows\System32\notepad.exe を指す。二つ目の C:\Windows\notepad.exe が指されることはない。

もし「XXXX というプログラム名で開けないんだけど?」という問題に見舞われたら、この where コマンドを試してみるといい。一番上に意図しないフォルダパスが入っていたり、そもそもプログラム XXXX が格納されたフォルダパスが登録されていなかったりする。


notepad.exe じゃなくて notepad で開けるんだけど、どうして?

鋭いですね。そうです、メモ帳は実は notepad.exe ではなく notepad でも開けます。C:\Windows\System32\notepad なんてファイルは存在しないにもかかわらず。なぜでしょう?

結論をいうと PATHEXT という環境変数(設定の一種)のおかげだ。

ここまでPATH は「この中に入ってるフォルダパスで補っていく」ものだと述べたが、PATHEXT は「この中に入ってる 拡張子 で補っていく」ものである。


PATHEXT の仕組みはどうなってんの?

PATHEXT は結局のところ「拡張子」の集まり(を格納した設定)でしかない。

まず中身は以下のようになっている。

.COM;.EXE;.BAT;.CMD;...

読みづらいが、わかりやすく書くとこうなる。


  • PATHEXT の中身


    • .COM

    • .EXE

    • .BAT

    • .CMD

    • ...



続いて、この PATHEXT がどう使われるかだが、Windows は、与えられたプログラム名を開く時に、そのプログラム名に拡張子が無い場合に限り 以下のようなロジックを用いる。たとえば notepad を与えたとすると、



  • notepad.com が存在するか調べる、存在するならそれを開いておしまい

  • 存在しないなら、


  • notepad.exe が存在するか調べる、存在するならそれを開いておしまい

  • 存在しないなら、


  • notepad.bat が存在するか調べる、存在するならそれを開いておしまい

  • 存在しないなら、


  • notepad.cmd が存在するか調べる、存在するならそれを開いておしまい

  • 存在しないなら、

  • ...

このようになる。

メモ帳を notepad で開ける理由は、PATH によってフルパスが補われているから、だけではない。PATHEXT によって拡張子( この場合は .exe )が補われているから、でもあるのだ。


おわりに

「PATH を通す」の意味をできるだけわかりやすく説明する試みをしてみました。いかがでしたでしょうか。参考になれば幸いです。

私もまだまだ勉強中ですので、コメント等ありましたらぜひお願いします


(おまけ) PATH と PATHEXT の適用アルゴリズム

PATH と PATHEXT がどのように作用するのか、を理解するのに、人によってはコードで読んだ方が早いかもしれない。というわけで(私の想像だが) where コマンドの実装を Python で書いてみた。

# -*- coding: utf-8 -*-


import os
import sys

def has_not_extension(path):
''' 拡張子の有無 = `.` の有無、だと思う(たぶん) '''
return path.find('.')==-1

PATH = os.environ['PATH'].split(';')
PATHEXT = os.environ['PATHEXT'].split(';')

if len(sys.argv)<=1:
print('<where2 コマンドのヘルプを出す>')
exit(0)
filename_you_want_to_open = sys.argv[1]

fullpath_you_want_to_open = None
found_fullpaths = []

# カレントディレクトリからの相対アクセス分.
PATH.insert(0, os.getcwd())

for a_folderpath in PATH:
fullpath_candidate = os.path.join(a_folderpath, filename_you_want_to_open)

# 入力ファイル名に拡張子が無い場合は PATHEXT で補っていく.
if has_not_extension(fullpath_candidate):

# 拡張子が無いそのパス自体も有効なパスかもしれない.
# 例: C:\Program Files\Git\usr\bin\notepad
# Git for Windows が用意してるメモ帳のラッパー?
fullpath_candidate_without_ext = fullpath_candidate
if os.path.exists(fullpath_candidate_without_ext):
fullpath_you_want_to_open = fullpath_candidate_without_ext
found_fullpaths.append(fullpath_you_want_to_open)
continue

for a_ext in PATHEXT:
fullpath_candidate_real = '{:}{:}'.format(fullpath_candidate, a_ext)
if os.path.exists(fullpath_candidate_real):
fullpath_you_want_to_open = fullpath_candidate_real
found_fullpaths.append(fullpath_you_want_to_open)
continue

if os.path.exists(fullpath_candidate):
fullpath_you_want_to_open = fullpath_candidate
found_fullpaths.append(fullpath_you_want_to_open)
continue

if fullpath_you_want_to_open==None:
print('情報: 与えられたパターンのファイルが見つかりませんでした。')
exit(1)

for fullpath in found_fullpaths:
fullpath_for_display = fullpath.lower()
print(fullpath_for_display)

使い方:

$ 上記スクリプトを where2.py で保存する


$ where notepad
C:\Windows\System32\notepad.exe
C:\Windows\notepad.exe

$ python where2.py notepad
c:\windows\system32\notepad.exe
c:\windows\notepad.exe

出力は小文字化しているが、本家 where コマンドとほぼ結果は同じになる(と思う)。