WSLには、通常のLinuxにはない機能として、Windowsのプログラムを起動できる「Win32相互運用性」(Win32 Interop)がある。
Win32相互運用性には、「Win32側からWSLのプログラムを実行する」、「WSL側からWin32プログラムを実行する」(今回解説)、「Win32とWSLで環境変数を共有する」(次回解説予定)の3つの機能がある。「Win32側からWSLのプログラムを実行する」の基本的な動作に関しては、「Windows Subsystem for Linuxガイド 第2回 コマンド編」に解説がある。
解説を行う前に用語を確認しておく。WSL側シェルはWSLディストリビューションにより違いがあるが、ここではLinuxで広く使われているbashであると仮定して説明を進める。以後bashと表記したらWSL側のシェルであることを理解しておいていただきたい。
WSL側で利用する「WSL側ファイルシステム」と「ドライブファイルシステム」のパスを「WSL側パス」と表記する。これは、いわゆるスラッシュ区切りのLinux形式パスである。
これに対して「Win32側ファイルシステム」と「wsl$ファイルシステム」のパスを「Win32側パス」と表記する。WSLのファイルシステムに関しては、「Windows Subsystem for Linuxガイド 第4回 ファイルシステム編」を参照されたい。
なお確認は、Windows 10 Ver.21H2とWindows 11 Ver.21H2で行い、UbuntuディストリビューションをWSL2で動作させて行った。
Win32相互運用性の実際
WSL側でのWin32相互運用性では、Win32側のコマンドプロンプトなどと違って、実行プログラムの拡張子を省略できない。このため、たとえば、メモ帳を起動するには必ず「notepad.exe」などと正しい実行ファイル名を指定する必要がある。
起動できるのは、デスクトップアプリケーションの実行ファイル形式(WindowsのPE形式)だけになる。正確な判定ではないが、拡張子がexe(もしくはcom)になっている実行ファイルのみが起動可能で、たとえば、UWPアプリケーションや、Windows標準のBatchファイルなどは、直接起動できない。ただし、これには後述するいくつか対処方法がある。
実行ファイルのパスだが、WSL側では、Win32コマンドは、ドライブファイルシステムのパスとして表現する必要がある。たとえば、“c:\Program Files\GIMP 2\bin\”にWin32コマンド“”があったとき、bash側では、これを
'/mnt/c/Program Files/GIMP 2/bin/gimp-2.10.exe'
と指定して起動できる。パスにスペースが含まれているために全体をシングルクオートでくくる必要があること、WSL側パスであることに注意されたい。なお、bashでは、Linuxコマンドと同じくPATH環境変数を使って、パスを省略したコマンドの実行が行える。
Win32コマンドの引数に指定されるパスは、原則、Win32側のファイルパスを指定する。ただし、Win32パス形式のパス区切り文字である逆スラッシュ“\”は、bashではエスケープ文字として認識される。方法としては、前記のようにパス全体をシングルクオートでくくるか、逆スラッシュを“\”としてエスケープ文字の意味を打ち消して指定するかのどちらかを使う。
bashのスクリプトなどで、どうしてもWSL側パスを引数に指定しなければならない場合には、WSLディストリビューション内で利用できる“wslpath”コマンドを使う。これについては後述する。
PATH環境変数とWin32相互運用性
WSL2では標準で、Win32側のPATH環境変数がWSL側シェルのPATH環境変数に追加される。
このPATH環境変数の追加は、/etc/wsl.conf(以下wsl.confと表記する)で制御ができる。具体的には、wsl.confの“[interop]”セクションの“appendWindowsPath”キーで、指定を行う(表01)。省略値は、trueで、この値のとき、WSLはディストリビューションの起動時にWin32側のPATH環境変数の内容を、WSL側パスに変換してbashのPATHに追加する。falseが指定されている場合、PATHの追加は行われない。この場合でもフルパスを指定することでWin32コマンドの起動は可能だ。
“enabled”キーは、WSL側でのWin32相互運用性の有効無効を指定する。
直接指定できないコマンドを実行させる
Win32相互運用性では、PE形式のWin32実行ファイルだけが起動できる。Windowsでは、基本的には、これらにはexeまたはcomという拡張子が付けられている。これには、いわゆるGUIコマンドなども含まれており、たとえば、notepad.exeでメモ帳を起動することが可能だ。
Windowsのコマンドプロンプトなどから起動できるが、WSLのWin32相互運用性で直接起動できないプログラムには「cmd.exeの内部コマンド」、「同BATCHファイル」、「UWPのアプリ実行エイリアス」がある。
cmd.exeなどの内部コマンドやbatchファイル、アプリ実行エイリアスに関しては、cmd.exeを起動し、その引数としてコマンドを指定しておく。具体的には、「cmd.exe␣ /c␣〈コマンド名〉」とする。たとえば、cmd.exeの内部コマンドであるコードページコマンド(chcp)を実行するには、
cmd.exe /c chcp
とする。C:\temp\test.batというバッチファイルなら
cmd.exe /c 'c:\temp\test.bat'
とすればよい。
カレントディレクトリがドライブファイルシステム以外では警告メッセージが表示されるが実行には問題ない(写真01)。“/mnt/c”などをカレントディレクトリとして実行すれば警告は表示されない。
アプリ実行エイリアスも同様にcmd.exeを介して起動できる。Windows Terminal(wt.exe)を起動したければ、
cmd.exe /c wt.exe
とすればよい。なお、アプリ実行エイリアスは、開発者が勝手に決めることができるため、実行時に他のアプリと衝突する可能性がある。これは、Windows 10ならば「設定 ⇒ アプリ ⇒ アプリと機能 ⇒ アプリ実行エイリアス」で、Windows 11なら「設定 ⇒ アプリ ⇒ アプリの詳細設定 ⇒ アプリ実行エイリアス」で制御ができる。
アプリ実行エイリアスが定義されているUWPアプリケーションは、この設定ページに表示される。逆にいうと、ここに表示されなUWPアプリケーションには、アプリ実行エイリアスが定義されていない。
Windows 10以降で、アプリ実行エイリアスを持たないUWPアプリケーションなどを起動する方法に「URI起動」(URL起動とも)がある。これも開発時に指定するものだが、これを定義しているアプリケーションは多い。特にWindowsに標準添付されるUWPアプリケーションの大半がこれを定義している。Windows側の機能である設定アプリなどもURI起動が可能だ。URI起動には、cmd.exeの組み込みコマンドであるstartを使う。
たとえば、Windows標準の電卓プログラムを起動するには“ms-calculator”をスキーマとするURIを使い
cmd.exe /c start ms-calculator:
とする。URIなのでスキーマ末尾にコロンを付けることに注意されたい。ここで指定するスキーマは、Windows 10ならば「設定 ⇒ アプリ ⇒ 既定のアプリ ⇒ プロトコルごとに既定のアプリを選ぶ」で、Windows 11なら「設定 ⇒ アプリ ⇒ 既定のアプリ ⇒ リンクの種類で既定値を選択する」(写真02)で確認することが可能だ。このページに表示されるアプリケーション名の下にある「URL:」で始まる記述が、各アプリケーションの起動用スキーマである。
URI起動は、Windows PowerShellを使っても調べることができる。これに関しては「窓辺の小石(67) URIの謎を解け」を参照されたい。
同様に設定アプリ内のページもURI起動で開くことができる。「システム ⇒ ディスプレイ」を開くなら、
cmd.exe /c start ms-settings:display
などとする。設定アプリのURIに関しては、Microsoftのサイトの「Windows 設定アプリの起動 - ms-settings: URI スキーム リファレンス」に解説がある。
こうした方法を使うことで、Windowsのコマンドラインから実行可能なコマンドのほとんどを実行できる。
/usr/bin/wslpathでパスを変換する
WSL側の/usr/bin/wslpathを使うと、Win32側パスとWSL側パスの相互変換が行える。Linux側のコマンドなので、基本的には、bashから呼び出すが、Win32相互運用性と組み合わせることで、cmd.exe上でも利用することができる。
wslpathは、「wslpath␣〈オプション〉␣〈パス〉」として利用する。引数として指定した〈パス〉は、オプション(表02)に従って変換される。bash側のLinuxコマンドで使う場合(Win32側パスをWSL側パスに変換)には、wslpathコマンドを“$(”~“)”または逆クオートで囲むコマンド置換を使うことで、変換結果をコマンドラインの引数として渡すことが可能になる。たとえば、notepad.exe(メモ帳)でWSL側パスの/home/User/test.txtを開く場合、bash上で
notepad.exe $(wslpath -w /home/user01/test.txt)
とする(写真03)。あるいは逆にcmd.exeでWin32側パスを使う場合に、
wsl -- cat $(wslpath -u "d:\Temp\test.txt")
とすることができる。
bashからWin32コマンドが利用できるため、Windowsのコマンドからの様々な情報を便利なLinuxのコマンドで処理できる。並べ替えや文字列検索などは基本的なコマンドがWindowsにも用意されているが、Linuxのコマンドにはおよばない。これまで面倒だったWindowsの情報抽出などがWSLを使うことで簡単になる。