🤖

WSLでopenコマンドを用意する

2022/03/09に公開
4

TL;DR

WSLでMacのopenコマンドみたいなのが欲しければ、以下を.zshrcに書く。

function open() {
    if [ $# != 1 ]; then
        explorer.exe .
    else
        if [ -e $1 ]; then
            cmd.exe /c start $(wslpath -w $1) 2> /dev/null
        else
            echo "open: $1 : No such file or directory" 
        fi
    fi
}

zshでしか試していないが、たぶんbashでも似たような感じでいけると思う。

エクスプローラによるopen

Macのターミナルでは、open filenameとすると、そのファイルを関連付けられたアプリで開くことができる。また、open .などとするとFinderでカレントディレクトリが開いて便利だ。

WindowsのWSLで似たようなことがしたくて、

alias open=explorer.exe

としていた。これでもほとんどの場合はうまくいくのだが、二つ問題があった。

一つは、デスクトップに同名のファイルがあるとそちらを開いてしまうこと。おそらくエクスプローラーのパスの検索順の問題だと思われる。

もう一つは、カレントディレクトリ以外のファイルを開けない事。例えば、カレントディレクトリにhoge.pdfがあるなら

open hoge.pdf

はできるが、

open dir/hoge.pdf
open ../hoge.pdf

などはできない。

cmd.exeによるopen

ということを愚痴ったら、「cmd.exeを使うのはどうか?」という方法を教えていただいた

cmd.exe /c start filename

として実行することで、ファイルを開くことができる。ただし、wslpathを使って、WSLのパスをWindows側に変換してやる必要がある。そこで、シェルの関数にして

function open() { cmd.exe /c start $(wslpath -w $1) }

とすれば、ほぼ所望の動作になる。

しかし、これでファイルを開くと、いちいち

$ open test.pdf
'\\wsl.localhost\Ubuntu\home\username\path\to\file'
上記の現在のディレクトリで CMD.EXE を開始しました。
UNC パスはサポートされません。Windows ディレクトリを既定で使用します。

と言われてしまう。また、存在しないファイルを指定した場合、コマンドプロンプトが開いてしまう。さらに、引数を指定しないで実行した場合「このusageリンクを開くには新しいアプリが必要です」みたいなダイアログが出てしまう。

これをもう少しなんとかしましょう、というのが本稿の目的である。

cmd.exeによるopen(改)

まず引数の数チェックをしよう。引数なしの場合、Macのopenのようにusageを表示してもよいが、open .と同じにしてしまった方が便利だろう。それならエクスプローラで良い。

function open() {
    if [ $# != 1 ]; then
        explorer.exe .
    fi
}

次に、引数が指定された場合、そのファイルの存在確認をしよう。ファイルがあればそのまま開き、そうでなければエラーを表示する。この時、cmd.exeの出力を2> /dev/nullに流してしまおう。

if [ -e $1 ]; then
    cmd.exe /c start $(wslpath -w $1) 2> /dev/null
else
    echo "open: $1 : No such file or directory" 
fi

以上をまとめると冒頭のコマンドになる。

参考URL

GitHubで編集を提案

Discussion

gekalgekal

下記アリスを使っていますが、ファイルの開きを考えていませんでした。
参考になりました。

alias open=explorer.exe
H.HiroH.Hiro

bashだとこの関数だけで「open」の後ろのファイル名補完が効いたのですが、zshでは何故かファイル名補完が効きませんでした(WSLのUbuntuのzsh 5.8で実行)。以下を追加で書いておく必要がありました。

compdef _open_completion open
function _open_completion {
  _files
  return 1;
}
ロボ太ロボ太

情報ありがとうございます。うちも同じ環境(WSL+zsh 5.8)ですが、普通にファイル名補完が効きますね。compinitが何かしているのかと、.zshrcを無効にしてopenだけ定義してやってみてもファイル補完されました。謎です。

H.HiroH.Hiro

ありがとうございます。
私の.zshrcに書いてある別の設定が影響しているのかもしれません。探ってみようと思います。