わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

利用可能なドライブレターを,zshのfunctionで

数日前より,WSL (Windows Subsystem for Linux)を使い始めました.Microsoft StoreでUbuntu 18.04 を入手し,「Windows の機能の有効化または無効化」で「Windows Subsystem for Linux」にチェックを入れてから,再起動.こまごまとした作業をしたのち,rbenvでrubyの2.6.0-devをインストールし,いくつかのRubyスクリプトが動くのを確認しました.
CygwinからWSLへの移行も,可能そうだなと思いつつ,気になったのはドライブレターの扱いです.Windowsの(あるいはコマンドプロンプトで指定する)ドライブ名の書き方は「C:」ですが,これはCygwinだと「/cygdrive/c」に対応し,WSLでは「/mnt/c」になります.
zshの設定ファイルに手を加えてみます.久しぶりに.zshrcを開いて見ると,uname -srの出力をもとに,linuxか,cygwinかを判定していました.WSLのシェルで,uname -srを実行すると,「Linux 4.4.0-17134-Microsoft」と出ました.設定に反映させましょう.

if [ -f $ZDOTDIR/.archi.wsl ]; then export ARCHI="wsl"
elif [ -f $ZDOTDIR/.archi.linux ]; then export ARCHI="linux"
elif [ -f $ZDOTDIR/.archi.cygwin ]; then export ARCHI="cygwin"
elif [ -f $ZDOTDIR/.archi.dummy ]; then export ARCHI="dummy"
elif which uname >& /dev/null; then
    case "`uname -sr`" in
	Linux*Microsoft); export ARCHI="wsl" ; touch $ZDOTDIR/.archi.$ARCHI ;;
	Linux*);  export ARCHI="linux"  ; touch $ZDOTDIR/.archi.$ARCHI ;;
	CYGWIN*); export ARCHI="cygwin" ; touch $ZDOTDIR/.archi.$ARCHI ;;
	*);       export ARCHI="dummy"  ; touch $ZDOTDIR/.archi.$ARCHI ;;
    esac
else
    export ARCHI="dummy"
fi
zshrc_suffix="$ZDOTDIR/.zshrc.$suffix"
[ -f $zshrc_suffix ] && source $zshrc_suffix

次に開くファイルは,.zshrc.cygwinです.ドライブレターについて,環境変数をいくつも定義していました.実在しないものも,あえて定義しています.USBメモリなどを接続した際に,$Dなどを使用することになります.

export C="/cygdrive/c"; export DRIVEC="$C"
export D="/cygdrive/d"; export DRIVED="$D"
export E="/cygdrive/e"; export DRIVEE="$E"
export F="/cygdrive/f"; export DRIVEF="$F"
export G="/cygdrive/g"; export DRIVEG="$G"
export H="/cygdrive/h"; export DRIVEH="$H"
export I="/cygdrive/i"; export DRIVEI="$I"
export J="/cygdrive/j"; export DRIVEJ="$J"
export K="/cygdrive/k"; export DRIVEK="$K"
export L="/cygdrive/l"; export DRIVEL="$L"
export M="/cygdrive/m"; export DRIVEM="$M"
export N="/cygdrive/n"; export DRIVEN="$N"
export Y="/cygdrive/y"; export DRIVEY="$Y"
export Z="/cygdrive/z"; export DRIVEZ="$Z"

U="$C/Users/$USER"
T="$U/Desktop"

それでは,.zshrc.wslを新たに作成します.上記をコピーして貼り付け,cygdriveをmntに置換します.ついでに,WSLから見たCygwinのホームディレクトリを,環境変数Rに割り当てておきます.

export C="/mnt/c"; export DRIVEC="$C"
export D="/mnt/d"; export DRIVED="$D"
export E="/mnt/e"; export DRIVEE="$E"
export F="/mnt/f"; export DRIVEF="$F"
export G="/mnt/g"; export DRIVEG="$G"
export H="/mnt/h"; export DRIVEH="$H"
export I="/mnt/i"; export DRIVEI="$I"
export J="/mnt/j"; export DRIVEJ="$J"
export K="/mnt/k"; export DRIVEK="$K"
export L="/mnt/l"; export DRIVEL="$L"
export M="/mnt/m"; export DRIVEM="$M"
export N="/mnt/n"; export DRIVEN="$N"
export Y="/mnt/y"; export DRIVEY="$Y"
export Z="/mnt/z"; export DRIVEZ="$Z"

U="$C/Users/$USER"
T="$U/Desktop"
R="$E/cygwin/home/$USER"

WSL環境でzshを開き直し…無事に,$Cや$Tで参照できるようになりました.
さて上記のとおり,たくさん変数を定義したものの,ドライブ,より正確にはディレクトリとして実在しないものもあります.実在するディレクトリについてだけ,変数名と対応するディレクトリを出力させるよう,zsh用のfunctionを作ることにします.
処理としては,AからZまでのそれぞれについて,その名前の変数がセットされ,そして変数の値がディレクトリとして実在するときに,$付きの変数名と値を,出力するようにしてみます.試行錯誤の結果,以下のコマンドになりました*1

$ [[ -n "${T+1}" && -d $T ]] && echo "\$T=$T"
$T=/mnt/c/Users/takehikom/Desktop
$ [[ -n "${Q+1}" && -d $Q ]] && echo "\$Q=$Q"
〔何も表示されない〕

「AからZまで」は,Rubyを使って自動生成させました.irbを実行してから,「('A'..'Z').each{|c| puts " -n \"${#{c}+1}\" && -d $#{c} && echo \"\\$#{c}=$#{c}\""}」で,一通り出ました.
出力のためのfunctionは,アーキテクチャを問わず使えそうなので,.zshrcに追加しました.

function print-drive-letter () {
    [[ -n "${A+1}" && -d $A ]] && echo "\$A=$A"
    [[ -n "${B+1}" && -d $B ]] && echo "\$B=$B"
    [[ -n "${C+1}" && -d $C ]] && echo "\$C=$C"
    [[ -n "${D+1}" && -d $D ]] && echo "\$D=$D"
    [[ -n "${E+1}" && -d $E ]] && echo "\$E=$E"
    [[ -n "${F+1}" && -d $F ]] && echo "\$F=$F"
    [[ -n "${G+1}" && -d $G ]] && echo "\$G=$G"
    [[ -n "${H+1}" && -d $H ]] && echo "\$H=$H"
    [[ -n "${I+1}" && -d $I ]] && echo "\$I=$I"
    [[ -n "${J+1}" && -d $J ]] && echo "\$J=$J"
    [[ -n "${K+1}" && -d $K ]] && echo "\$K=$K"
    [[ -n "${L+1}" && -d $L ]] && echo "\$L=$L"
    [[ -n "${M+1}" && -d $M ]] && echo "\$M=$M"
    [[ -n "${N+1}" && -d $N ]] && echo "\$N=$N"
    [[ -n "${O+1}" && -d $O ]] && echo "\$O=$O"
    [[ -n "${P+1}" && -d $P ]] && echo "\$P=$P"
    [[ -n "${Q+1}" && -d $Q ]] && echo "\$Q=$Q"
    [[ -n "${R+1}" && -d $R ]] && echo "\$R=$R"
    [[ -n "${S+1}" && -d $S ]] && echo "\$S=$S"
    [[ -n "${T+1}" && -d $T ]] && echo "\$T=$T"
    [[ -n "${U+1}" && -d $U ]] && echo "\$U=$U"
    [[ -n "${V+1}" && -d $V ]] && echo "\$V=$V"
    [[ -n "${W+1}" && -d $W ]] && echo "\$W=$W"
    [[ -n "${X+1}" && -d $X ]] && echo "\$X=$X"
    [[ -n "${Y+1}" && -d $Y ]] && echo "\$Y=$Y"
    [[ -n "${Z+1}" && -d $Z ]] && echo "\$Z=$Z"
}

実行してみます.Cygwinの端末では:

$ print-drive-letter
$C=/cygdrive/c
$E=/cygdrive/e
$F=/cygdrive/f
$T=/cygdrive/c/Users/takehikom/Desktop
$U=/cygdrive/c/Users/takehikom
$Z=/cygdrive/z

次に,WSLのUbuntuでは:

$ print-drive-letter
$C=/mnt/c
$E=/mnt/e
$F=/mnt/f
$R=/mnt/e/cygwin/home/takehikom
$T=/mnt/c/Users/takehikom/Desktop
$U=/mnt/c/Users/takehikom
$Z=/mnt/z

*1:bashでも動作確認しました.