タイトルが長いのはご容赦ください。ここでは、WSL で利用するシェルスクリプトを作成した時に得られたバッドノウハウを 3 点紹介します。 このシェルスクリプトを作成する時は知らなかったのですが、Sudo for WSL (wsl-sudo)1 というものがあります。試してみたことはありません。バッドノウハウよりも今使えるものが欲しいという方はこちらを試してみてはどうでしょうか?
作成したシェルスクリプトの概要
- WSL のコマンドシェル or シェルスクリプトから起動することを想定
- 引数で指定されたバッチファイルを管理者権限で起動します
- バッチファイルは Windows の %TEMP% ディレクトリに存在するものとします
作成したシェルスクリプト2
1 #!/bin/sh
2 runfile="$1"
3 cd /mnt/c
4
5 u_psexe="/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe"
6 m_psexe=$(wslpath -a -m "$u_psexe")
7
8 u_cmdexe="/mnt/c/Windows/System32/cmd.exe"
9 m_cmdexe=$(wslpath -a -m "$u_cmdexe")
10
11 # Get value of %TEMP% with long file name
12 w_temp=$($u_psexe 'Write-Host (Get-Item -LiteralPath $Env:TEMP).FullName' < /dev/null | sed -e 's/\r$//')
13 u_temp=$(wslpath -a -u "$w_temp")
14 m_temp=$(wslpath -a -m "$u_temp")
15
16 # Execute $runfile as admin
17 cd "$u_temp"
18 case "$runfile" in
19 *.bat)
20 $u_psexe -NoProfile Start-Process -Wait -Verb RunAs -WorkingDirectory "$m_temp" -FilePath "$m_cmdexe" -ArgumentList "'/C $m_temp/$runfile'" < /dev/null
21 ;;
22 *.ps1)
23 $u_psexe -NoProfile Start-Process -Wait -Verb RunAs -WorkingDirectory "$m_temp" -FilePath "$m_psexe" -ArgumentList "'-NoProfile -ExecutionPolicy RemoteSigned -File $m_temp/$runfile'" < /dev/null
24 ;;
25 esac
コマンド説明
wslpath
バッドノウハウの前に、6, 9, 13, 14 行目で使われている wslpath
コマンドについて簡単に説明します。WSL でディストリビューションをインストールすると自動的に作成されるようです。実態は以下のように /init
へのシンボリックリンクです。
$ ls -l $(which -a wslpath)
lrwxrwxrwx 1 root root 5 Nov 19 15:28 /bin/wslpath -> /init
lrwxrwxrwx 1 root root 5 Nov 19 15:28 /usr/bin/wslpath -> /init
wslpath
を引数なしで起動すると使用例が表示されます。Windows のパス表記を UNIX 系の表記に変換したり、その逆をしたりする機能があります。下表に示すようなパス表記の変換ができます。
$ wslpath
wslpath: Invalid argument
Usage:
-a force result to absolute path format
-u translate from a Windows path to a WSL path (default)
-w translate from a WSL path to a Windows path
-m translate from a WSL path to a Windows path, with '/' instead of '\'
EX: wslpath 'c:\users'
オプション指定 | 出力例 |
---|---|
-u | /mnt/c/Windows/System32 |
-w | C:\Windows\System32 |
-m | C:/Windows/System32 |
今回作成したシェルスクリプトでは、パス名を含むシェル変数にどの形式のパス名が設定されているかを示すため、u_
, w_
, m_
のプリフィクスをつけてあります。
バッドノウハウ
(その 1) 3 行目
cd /mnt/c
cmd.exe などは WSL 側のパスを理解できないようです。WSL から cmd.exe を起動すると、以下のようなメッセージが表示されます。一旦 、C ドライブ直下などに避難して回避します。
'\\wsl.localhost\Ubuntu-24.04\home\username’
上記の現在のディレクトリで CMD.EXE を開始しました。
UNC パスはサポートされません。Windows ディレクトリを既定で使用します。
(その 2) 11 行目
環境変数 TEMP のパス名がショートパス名になっている場合があります。ショートパス名は wslpath
では扱えないようです、あらかじめここでロングパス名に展開します。
(その 3) 12, 20, 23 行目
Windows 側のコマンドを実行すると、なぜか標準入力が吸い取られます。この問題に関連する記事がこちらにあります。< /dev/null
によるリダイレクトはその対策です。この記事の説明がシンプル過ぎるので、わかりやすそうな例を示します。
cat file.txt | while read line; do
…
echo line=$line
なんとか.exe
…
done
このようなシェルスクリプトの場合、file.txt に複数行あったとしても、なんとか.exe
が起動する際に、標準入力が全部吸い込まれてしまうため、ループは 1 回で終了してしまいます。line=...
は file.txt の 1 行目だけが表示されます。
今回作成したシェルスクリプトをコマンド行から起動しているだけならば気がつかないかもしれません。このシェルスクリプトを別のシェルスクリプトに組み込んだ場合などで、実行時に標準入力が読み込み可能な状態だと、上記の問題が発生します。
-
Sudo for WSL (wsl-sudo) / 以下「What is this?」より抜粋
This tool allows you to run applications in windows elevated user mode from a non-elevated wsl shell. It has full terminal support, so you can run interactive applications like vim or a shell through it. ↩ -
UAC による権限の昇格が発生すると、ダイアログ・ウインドウが表示されます。これは手動で入力、もしくは、クリックして通過してください。スクリプトにより自動的に指定されたバッチファイルを起動しますが、無人で利用可能というわけではありません。 ↩