Windows 10 で Python ファイル実行時にコマンドライン引数が渡されない件

拡張子 .py に Python.exe を関連付け、かつ PATH と PATHEXT を通した状態で foobar.py に対して、

$ foobar -h

を実行してもヘルプが出ない。-h の部分が無視されて実行されてしまう。

この問題に対処したのでメモ。

前提

  • Windows 10 Pro
  • Python 3.7.4

対処方法

レジストリをいじる。

  • HKEY_CLASSES_ROOT\Applications\python.exe\shell\open\command キー
  • 既定エントリ

値を以下のように "%1" から %1 %* に変える。

"D:\bin1\python374\python.exe" "%1"

  ↓

"D:\bin1\python374\python.exe" %1 %*

ちなみに HKEY_CLASSES_ROOT\py_auto_file\shell\open\command をいじってもダメだった(assoc コマンドでは .py=py_auto_file なのだが)。

参考: Windows is not passing command line arguments to Python programs executed from the shell - Stack Overflow

Q: なんでこんな対処が必要?

Ans: 関連付けを解決する時に使われる assoc と ftype 設定の仕様だから

以下詳しく見ていく。

たとえば .py に D:\bin1\python374\python.exe を関連付けると、

$ D:\bin1\python374\python.exe foobar.py
→普通はこう書かなきゃいけないところが

$ foobar.py
→これで済むようになる

このようになる。この時、内部的には assoc と ftype により、以下のような設定になっている。

assoc .py=py_auto_file
ftype py_auto_file=D:\bin1\python374\python.exe %1 %*

ここで ftype については、ftype /? でヘルプを読んでみると、こう書いてある。

オープンコマンド内の %0 または %1 は、関連付けを使って開かれるファイル名で置き換えられます。……%* はすべてのパラメーターを取得し、

つまり、内部的には以下のようにして関連付けの解決が行われている。

foobar.py -h

  ↓ .py=py_auto_file だから ftype py_auto_file の設定に従おう

D:\bin1\python374\python.exe %1 %*

  ↓ %1 は「関連付けを使って開かれるファイル名」
  ↓ %* は「すべてのパラメーター」だから、

D:\bin1\python374\python.exe foobar.py -h

ここで、仮に ftype が D:\bin1\python374\python.exe %1 だとしよう( %* が足りない)。どうなるか。

foobar.py -h

  ↓ .py=py_auto_file だから ftype py_auto_file の設定に従おう

D:\bin1\python374\python.exe %1

  ↓ %1 は「関連付けを使って開かれるファイル名」

D:\bin1\python374\python.exe foobar.py

このようになってしまい、-h のコマンドライン引数部分が常にカットされてしまう結果となる。

参考:

Q: なんで Applications\python.exe だと直るけど py_auto_file だと直らないの?

Ans: 優先順位の問題で Applications\Python.exe の設定が優先される から(たぶん)。

Application Registration - Windows applications - Microsoft Docs を見ていると、どうもアプリの関連付け設定箇所は複数あり、かつ優先順位(priority) があるように読める。

記述は見当たらなかったが、HKEY_CLASSES_ROOT\XXXX よりも HKEY_CLASSES_ROOT\Applications\XXXX.exe の方が優先順位が高いのだと思われる。

つまり、HKEY_CLASSES_ROOT\Applications\Python.exe 側が %1 となっていたら、いくら HKEY_CLASSES_ROOT\py_auto_file 側を %1 %* にしても、使われるのは優先順位の高い Applications\Python.exe 側の %1 になる、という話。