これは dotfiles Advent Calendar 2019 の 18 日目の記事です。
WSL のユーザー向けに、過去の記事よりちょっと便利な open
コマンドの実装を紹介します。
ちなみに自分の dotfiles は こんな感じ で、デスクトップ版の Ubuntu でも使っています。
open
コマンドとは
まず open
コマンド(Ubuntu などでは xdg-open
など)とは、指定されたパスや URL をデフォルトのアプリケーションで開くコマンドです。
例えば Ubuntu の場合、xdg-open .
で Nautilus などのファイラーが、xdg-open https://qiita.com
で Chrome などのブラウザが、xdg-open ~/.bashrc
で VS Code などのエディターが起動するはずです。
便利ですね。
しかし WSL の場合は GUI がないため、これらのコマンドが上記のように機能しません。
WSL でも open
でエクスプローラーや Windows 側の Chrome なり VS Code なりを起動したいですよね?
これについては先人がおり、Qiita にも既に WSL から open という同様の記事が投稿されています。
今回はここで紹介されている open
の実装を見直し、より便利にアップグレードしてみました。
Windows10 1903 で WSL 内のディレクトリにも Windows で有効なパスが割り当てられた こともあり、具体的には以下のようなことが可能になっています。
- スペースを含むパスに対応した
- URL に対応した
-
open /
など Windows 側に実体のないファイルも開けるようになった
実装とその説明
とりあえずこんな感じになっています。
WSL ユーザーはこれを ~/.bashrc
に追記し、source ~/.bashrc
を実行すれば open
が使えるようになります。
open() {
if [ $# -ne 1 ]; then return 1; fi
if [ -e "$1" ]; then
local winpath=$(readlink -f "$1" | xargs -0 wslpath -w)
powershell.exe start "\"${winpath%?}\""
else
powershell.exe start "$1"
fi
}
まず 1 行目ですが、リリース情報を見て WSL かどうかの判定をしています。
判定方法は いくつか あるようですが、今回は POSIX 準拠でなるべくわかりやすそうなものを選択しました。
(まあ後で 3 か所ほど Bash の拡張を使ってしまっているのであまり意味はないかもですが。)
次の if
は引数が一つだけかのチェックで、一つでないときは early return しています。
このあたりまでは元の実装と大体同じ雰囲気です。
次の if
では指定されたパスが存在するかを確認し、URL などパスでない場合は else
でそのまま powershell.exe start
を呼び出しています。
元の実装はワンライナーでこの部分がなかったため、URL を処理できませんでした。
また元の実装では cmd.exe /c start
を使っていましたが、今回は 4U6U57/wsl-open を参考に powershell.exe start
を使っています。
入力がパスであった場合の処理も変更しており、ワンライナーをやめローカル変数 winpath
を作ってから powershell.exe start
にこれを渡すことで、powershell.exe start
による余計なログが出力されないようにしています。
(なぜローカル変数を作ることで余分なログが出なくなるのかは、正直よく分かっていません。)
ちなみに winpath
とは、wslpath -w
で指定された WSL 側のパスを Windows 側のパスに変換したものです。
wslpath
の前に readlink -f
でシンボリックを展開し、xargs
でコマンドをつなぐとき -0
でスペースを含むパスも扱えるようにしています。
あとは最後に "\"${winpath%?}\""
で、start
が正しく動作するよう両端に "
をつけたり -0
によるヌル文字を消したりしています。
拡張子とアプリの関連付けを変更する
open
で起動するアプリと拡張子との関連付けは、Windows10 の「設定」の「既定のアプリ」の下の「ファイルの種類ごとに既定のアプリを選ぶ」をクリックした画面で変更できます。
おまけ
自分は if uname -r | grep -q 'Microsoft'; then
のブロックにこんなコードも書いています。
if uname -r | grep -q 'Microsoft'; then
export LS_COLORS='ow=01;33'
ggl() {
if [ $# -eq 0 ]; then return 1; fi
open "https://www.google.com/search?q=$(echo "$@" | sed 's/+/%2B/g;s/ /+/g')"
}
if [ "${PWD,,}" = '/mnt/c/windows/system32' ]; then cd; fi
fi
まず最初の export LS_COLORS='ow=01;33'
は ls
で表示されるフォルダーの色を変更する設定です。
この記事 を参考に、/mnt/c
以下にある Windows 側のフォルダのシンボリックリンクを見やすいように黄色にしています。
次の ggl
は以下のツイートを参考に作った関数で、ターミナルから Google 検索ができるようになります。
open
は /mnt/c/Program\ Files\ \(x86\)/Google/Chrome/Application/chrome.exe
で置き換えても動きます。
こういうシェルスクリプト作っておくとターミナルからググれるので便利 pic.twitter.com/BDSroyqKJR
— うじまる🐔 (@uzimaru0000) 2019年10月31日
最後の if [ "${PWD,,}" = '/mnt/c/windows/system32' ]; then cd; fi
は Windows Terminal から WSL を使っている人向けの設定です。
VS Code のように右クリックのメニューから Windows Terminal を開けるようにした場合、ショートカットから起動すると /mnt/c/WINDOWS/system32
などがカレントディレクトリになってしまうのを修正します。
詳しくは microsoft/terminal#1060 を見るといいでしょう。
余談ですが Windows Terminal は現状でもかなり便利なのでおすすめです。
自分の dotfiles にも Windows Terminal の設定 が置いてあるので、興味のある人は是非使ってみてください。
参考文献
- https://qiita.com/aohmusi/items/a46e3267ab506cedd1ad
- https://devblogs.microsoft.com/commandline/whats-new-for-wsl-in-windows-10-version-1903/
- https://moyapro.com/2018/03/21/detect-wsl/
- https://github.com/4U6U57/wsl-open
- https://stackoverflow.com/questions/52691835/wsl-ubuntu-how-to-open-localhost-in-browser-from-bash-terminal
- https://www.kwbtblog.com/entry/2019/04/27/023411
- https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/start-process?view=powershell-5.1#parameters
- https://docs.microsoft.com/ja-jp/windows/uwp/launch-resume/launch-settings-app#apps
- https://twitter.com/uzimaru0000/status/1189705915001257984
- https://github.com/microsoft/terminal/issues/1060#issuecomment-559625588
- https://qiita.com/kawaz/items/211266021515b3f033a3