Windowsでシンボリックリンクを試してみる。

きっかけは、1つのファイルを別の名前で起動したら違う動きになるようなスクリプトを書く、でした。

 busybox なんかでは、同じ実行形式ファイルの名前を、lsにすればlsと同じ、cpとすればcpと同じ動作をするようにしてますが、Pythonスクリプトでそれと同じように argv[0] を調べて、その名前によって動作を変える、ということをしたい、ということです。

まずは argtest.py というファイルを作ります。

import sys
import pathlib

f = pathlib.Path(sys.argv[0])
print(sys.argv)
print(f.name)
print(__file__)

これを実行すると、

C:\Users\kats\projects\argtest>argtest.py
['C:\\Users\\kats\\projects\\argtest\\argtest.py']
argtest.py
C:\Users\kats\projects\argtest\argtest.py

C:\Users\kats\projects\argtest>py argtest.py
['argtest.py']
argtest.py
C:\Users\kats\projects\argtest\argtest.py

C:\Users\kats\projects\argtest>python argtest.py
['argtest.py']
argtest.py

のようになります。py または python を指定して実行するとファイル名のみ、直接実行するとフルパス名が argv[0] に入っているようです。

次にショートカットを作成してみます。コマンドプロンプトから作るのは WSH を呼び出すスクリプトが必要なようなので、エクスプローラーから行います。

作成すると、 "argtest.py - ショートカット.lnk" というファイルが作成されます。サフィックスの ".lnk" は拡張子を表示する設定にしないと表示されませんが、ショートカットにつく拡張子です。余談ですが、".lnk" をリネームで削除してもショートカットとして使えるようです。

C:\Users\kats\projects\argtest>"argtest.py - ショートカット.lnk"
['C:\\Users\\kats\\projects\\argtest\\argtest.py']
argtest.py
C:\Users\kats\projects\argtest\argtest.py

C:\Users\kats\projects\argtest>py "argtest.py - ショートカット.lnk"
  File "C:\Users\kats\projects\argtest\argtest.py - ショートカット.lnk", line 1
    L
SyntaxError: source code cannot contain null bytes

C:\Users\kats\projects\argtest>python "argtest.py - ショートカット.lnk"
  File "C:\Users\kats\projects\argtest\argtest.py - ショートカット.lnk", line 1
    L
SyntaxError: source code cannot contain null bytes

実行するとショートカットをダイレクトに起動した場合以外はエラーになります。また、ダイレクトに起動した場合でも argv[0] には元ファイルのファイル名が入っているようです。これだと、呼び出しファイル名で動作を変えることができません。

ちなみに、エディタによっては、ショートカットファイルを編集すると、その元ファイルを開いてくれるものもあるようです。

ショートカットでは argv[0] に元ファイル名しか入っていないと、動作を変えることができません。UNIX系OSではシンボリックリンクを実行形式ファイルに張ると、ちゃんと argv[0] にシンボリックリンクの名前が入ってくるので、Windows上でシンボリックリンクが使えないか調べてみました。

Windowsには標準コマンドで mklink というのがあるようです。mklinkではハードリンクも作成できるようですが、同一のファイルシステム内にしか作成できないということで、ここではシンボリックリンクを試します。

ちなみにmklinkの実行は管理者権限が必要で、通常のコマンドプロンプトから実行すると怒られます。

C:\Users\kats\projects\argtest>mklink argtest2.py argtest.py
argtest2.py <<===>> argtest.py のシンボリック リンクが作成されました

シンボリックリンクを作成しました。早速実行してみると、

C:\Users\kats\projects\argtest>argtest2.py
['C:\\Users\\kats\\projects\\argtest\\argtest.py']
argtest.py
C:\Users\kats\projects\argtest\argtest.py

C:\Users\kats\projects\argtest>py argtest2.py
['argtest2.py']
argtest2.py
C:\Users\kats\projects\argtest\argtest2.py

C:\Users\kats\projects\argtest>python argtest2.py
['argtest2.py']
argtest2.py
C:\Users\kats\projects\argtest\argtest2.py

となります。今度は直接実行した場合に元ファイル名が出てきました。なかなかうまくいかないもんです。がっくし。

余談ですが、開発者モードというのを有効にしてやると、管理者モードのコマンドプロンプトでなくてもmklinkは実行できるようです。が、セキュリティ的によろしくないのでやめておきます。

ついでに、ものは試しでハードリンクもやってみます。

C:\Users\kats\projects\argtest>argtest3.py
['C:\\Users\\kats\\projects\\argtest\\argtest3.py']
argtest3.py
C:\Users\kats\projects\argtest\argtest3.py

C:\Users\kats\projects\argtest>py argtest3.py
['argtest3.py']
argtest3.py
C:\Users\kats\projects\argtest\argtest3.py

C:\Users\kats\projects\argtest>python argtest3.py
['argtest3.py']
argtest3.py
C:\Users\kats\projects\argtest\argtest3.py
これだとバッチリみたいですね。うーむ。

Windowsでシンボリックリンクを試してみる。

きっかけは、1つのファイルを別の名前で起動したら違う動きになるようなスクリプトを書く、でした。  busybox なんかでは、同じ実行形式ファイルの名前を、lsにすればlsと同じ、cpとすればcpと同じ動作をするようにしてますが、Pythonスクリプトでそれと同じように argv...