はじめに
WSL(Windows Subsystem for Linux)を標準ターミナルとして使おうとしたら、ちょっとした問題があったので忘備録的に残しておきます。
実行環境は以下のとおりです。
- Windows : Windows 10 Pro
- WSL : Ubuntu 18.04.2 LTS
やりたかったこと
WSLから、Windowsでインストールしたnodeやnpmコマンドを使用したかったのですが、うまくいきませんでした。
$ node
Command 'node' not found, but can be installed with:
sudo apt install nodejs
原因
原因は2つほどありました。
- WSL側に必要な環境変数が反映されていない
- 「.exe」を省略してコマンドを実行することができない
原因1 : WSL側に必要な環境変数が反映されていない
WSLを起動します。
> wsl
WSLにログインし、「envコマンド」でWSLの環境変数を確認してみます。(一部内容を省略してます)
user@host /mnt/c/Users/testuser
$ env
.
.
.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/mnt/c/Program Files (x86)/Common Files/Oracle/Java/javapath:/mnt/c/Program Files (x86)/Intel/iCLS Client/:/mnt/c/Program Files/Intel/iCLS Client/:/mnt/c/Windows/system32:/mnt/c/Windows:/mnt/c/Windows/System32/Wbem:/mnt/c/Windows/System32/WindowsPowerShell/v1.0/:/mnt/c/Program Files (x86)/Intel/Intel(R) Management Engine Components/DAL:/mnt/c/Program Files/Intel/Intel(R) Management Engine Components/DAL:/mnt/c/Program Files (x86)/Intel/Intel(R) Management Engine Components/IPT:/mnt/c/Program Files/Intel/Intel(R) Management Engine Components/IPT:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Program Files (x86)/Common Files/Adobe/AGL:/mnt/c/Program Files (x86)/Windows Live/Shared:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/Program Files/Intel/WiFi/bin/:/mnt/c/Program Files/Common Files/Intel/WirelessCommon/:/mnt/c/Program Files/dotnet/:/mnt/c/Program Files/Microsoft SQL Server/130/Tools/Binn/:/mnt/c/Program Files/Java/jdk1.8.0_191/bin:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA NvDLISR
.
.
.
LESSOPEN=| /usr/bin/lesspipe %s
_=/usr/bin/env
「PATH」の中身などは、初期設定でWindowsの環境設定をインポートしてくるようです。
また、WSL側からもWindowsのフォルダ構造が参照できるよう/mnt/c/Program Files/...
のようにパスが変換されています。
一方で、それ以外の独自に追加した環境変数(NODE_PATHなど)は反映されていませんでした。
対応方法
Windows側の環境変数を追加で読み込ませる機能として、「WSLENV」というしくみがあるようです。
詳細については以下の記事をご覧ください。
対応手順としては以下のようになります。
- Windows側で、環境変数「WSLENV」の値に読み込ませたい環境変数名を追加する
- WSLを起動し、環境変数が追加されていることを確認する
1つずつ見ていきます。
1. 「WSLENV」の設定
Windows側の環境変数はGUIで設定していきます。
コントロールパネル -> システムとセキュリティ -> システム -> システムの詳細設定と進み、
表示されたダイアログボックスから[詳細設定]タブに移動し、[環境変数]を押下します。
ユーザー環境変数に「WSLENV」変数を追加します。
[新規]ボタンを押下し、変数名を「WSLENV」、変数値を以下のように記載します。
[変数名1]/[オプション]:[変数名2]/[オプション]:[変数名3]/[オプション]
Image may be NSFW.
Clik here to view.
追加したい変数名を記入し、「/」のあとにオプションを付与します。
複数指定したい場合はコンマ「:」で変数名をつないでいきます。
オプション | 説明 |
---|---|
p | WindowsのパスとLinuxのパスを変換して環境変数を引き継ぐ |
l | 複数のパスを持つ環境変数を引き継ぐ、パスの区切りは「:」に変換される |
u | Windows環境からLinux環境を起動した際に、環境変数を引き継ぐ |
w | Linux環境からWindows環境を起動した際に、環境変数を引き継ぐ |
オプションの詳しい説明については下記の記事を参照してください。
参考記事
WSL その128 - Windowsの環境変数とLinuxの環境変数を相互に引き継ぎ可能に
2. 設定の確認
「WSLENV」の設定が完了したら、WSLを起動します。
コンソールを開いたままだと「WSLENV」が反映されないため注意してください。
WSLにログイン後、「envコマンド」で環境変数を確認します。(一部内容を省略してます)
user@host /mnt/c/Users/testuser
$ env
.
.
.
LANG=C.UTF-8
NODE_PATH=/mnt/c/Program Files (x86)/Nodist/bin/node_modules:/%NODE_PATH%
WSL_DISTRO_NAME=Ubuntu
NODIST_X64=/1
NODIST_PREFIX=/mnt/c/Program Files (x86)/Nodist
.
.
.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/mnt/c/Program Files (x86)/Common Files/Oracle/Java/javapath:/mnt/c/Program Files (x86)/Intel/iCLS Client/:/mnt/c/Program Files/Intel/iCLS Client/:/mnt/c/Windows/system32:/mnt/c/Windows:/mnt/c/Windows/System32/Wbem:/mnt/c/Windows/System32/WindowsPowerShell/v1.0/:/mnt/c/Program Files (x86)/Intel/Intel(R) Management Engine Components/DAL:/mnt/c/Program Files/Intel/Intel(R) Management Engine Components/DAL:/mnt/c/Program Files (x86)/Intel/Intel(R) Management Engine Components/IPT:/mnt/c/Program Files/Intel/Intel(R) Management Engine Components/IPT:/mnt/c/Program Files (x86)/NVIDIA Corporation/PhysX/Common:/mnt/c/Program Files (x86)/Common Files/Adobe/AGL:/mnt/c/Program Files (x86)/Windows Live/Shared:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0/:/mnt/c/WINDOWS/System32/OpenSSH/:/mnt/c/Program Files/Intel/WiFi/bin/:/mnt/c/Program Files/Common Files/Intel/WirelessCommon/:/mnt/c/Program Files/dotnet/:/mnt/c/Program Files/Microsoft SQL Server/130/Tools/Binn/:/mnt/c/Program Files/Java/jdk1.8.0_191/bin:/mnt/c/Program Files/NVIDIA Corporation/NVIDIA NvDLISR
.
.
.
WSLENV=NODE_PATH/pu:NODIST_PREFIX/pu:NODIST_X64/pu
LESSOPEN=| /usr/bin/lesspipe %s
_=/usr/bin/env
「WSLENV」と、その中で指定した環境変数が個別に読み込まれていることが確認できます。
これで環境変数が反映されない問題は解決したので、もう1つの問題を確認していきます。
原因2 : 「.exe」を省略してコマンドを実行することができない
原因1の対応で、環境変数のパスは正常に読み込まれているはずです。
ためしにnpm
と打ってみます。
$ npm
Command 'npm' not found, but can be installed with:
sudo apt install npm
「そんなコマンドはないよ」と言われてしまいました。
「aptコマンド」でインストールを勧められるあたり、Windows側の「npmコマンド」は読み込まれていないようです。
今度はnpm.exe
と拡張子付きで叩いてみます。
$ npm.exe
Usage: npm <command>
where <command> is one of:
access, adduser, audit, bin, bugs, c, cache, ci, cit,
clean-install, clean-install-test, completion, config,
create, ddp, dedupe, deprecate, dist-tag, docs, doctor,
edit, explore, fund, get, help, help-search, hook, i, init,
install, install-ci-test, install-test, it, link, list, ln,
login, logout, ls, org, outdated, owner, pack, ping, prefix,
profile, prune, publish, rb, rebuild, repo, restart, root,
run, run-script, s, se, search, set, shrinkwrap, star,
stars, start, stop, t, team, test, token, tst, un,
uninstall, unpublish, unstar, up, update, v, version, view,
whoami
.
.
.
一部省略してますが、ちゃんとマニュアルが表示されているので正常に読み込まれていることが分かります。
対応方法
「.exe」をつければ、正常にコマンドが実行できることが分かりました。
でも毎回「.exe」まで指定するのは面倒なので、エイリアスを登録して楽をしたいと思います。
エイリアスの登録
bashの設定ファイル.bashrc
の中にエイリアスを登録し、「.exe」なしでコマンドが実行できるよう設定します。
$ vim ~/.bashrc
vimの編集画面が開かれるので、以下のように.bashrc
に内容を追記してください。
alias [コマンド名]='[実行ファイル名]'
私は以下のように設定しました。
# aliases
alias node='node.exe'
alias npm='npm.exe'
編集が終わったら、「sourceコマンド」で.bashrc
を再度読み込ませて、エイリアスを反映させます。
$ source ~/.bashrc
「sourceコマンド」実施後、「.exe」なしでコマンドを実行できるか確認します。
$ npm
Usage: npm <command>
where <command> is one of:
access, adduser, audit, bin, bugs, c, cache, ci, cit,
clean-install, clean-install-test, completion, config,
create, ddp, dedupe, deprecate, dist-tag, docs, doctor,
edit, explore, fund, get, help, help-search, hook, i, init,
install, install-ci-test, install-test, it, link, list, ln,
login, logout, ls, org, outdated, owner, pack, ping, prefix,
profile, prune, publish, rb, rebuild, repo, restart, root,
run, run-script, s, se, search, set, shrinkwrap, star,
stars, start, stop, t, team, test, token, tst, un,
uninstall, unpublish, unstar, up, update, v, version, view,
whoami
.
.
.
無事に「.exe」なしで実行できました。
ちなみに設定したエイリアスの一覧は「aliasコマンド」で確認できます。
余談 : どんな実行ファイルがあるのか分からない場合
環境変数って、パスだけ見てもどんな実行ファイルがあるのか覚えてない人も多いかと思います。
私もそうだったので、実行ファイルの一覧を出力するワンライナーを書いてみました。
$ (IFS=$'\n' ; for i in `echo ${PATH} | sed -e 's/\:/\n/g' | grep "^/mnt" | grep -Ev "mnt/c/Windows|mnt/c/WINDOWS"` ; do find ${i} -type f -name "*.exe" ; done)
環境変数「PATH」に指定されているパスを1行ずつ取得し、そのパス内に「.exe」ファイルがあれば出力する仕組みになってます。
C:\Windows\System32配下などのOS固有のディレクトリは検索条件から排除しました。
それでも結構な数が出力されてしまいますが…
適当に書いたものですが、よければ確認程度にご活用ください。