WSL 上の cd
コマンドで Windows の絶対パスへ移動出来るようにします。
1. ソースコード
set -uoo pipefail posix
#
function cd_wsl() {
if [[ $# -gt 0 ]]; then
local -r last="${@:$#}"
if [[ "$last" =~ ^[A-Za-z]: ]]; then
builtin cd "${@:1:$#-1}" "$(wslpath "$last")"
return
fi
fi
builtin cd "$@"
}
alias cd=cd_wsl
cd 'C:\'
pwd
cd '/usr/lib'
pwd
/mnt/c
/usr/lib
2. 説明
2.1. wslpath
コマンド
WSL 上で wslpath
コマンドを使用することで、Windows のパスと WSL のパスの相互変換が可能です。
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'
※ wslpath
コマンドの使い方は wslpath 2> /dev/null
等で確認出来ます。
参考「ビルド 17046 - WSL のリリース ノート | Microsoft Learn」
2.2. Windows のパスと Linux のパスの判別
Windows ではファイル名に使用できない記号が多くあります。
しかし、ほとんどの Linux のディストリビューションで用いられるファイルシステム ext4 では、仕様上はスラッシュ /
、.
および ..
以外の記号を全て使用可能です。
そのため、厳密に「この文字さえ含まれていれば Linux のパスでなく Windows のパス」と断定することは出来ません。
ここでは、「ドライブ文字を含むかどうか」で簡易的に判別することにします。
ドライブ文字の有無は正規表現 ^[A-Za-z]:
で確認します。
[[ 'C:\' =~ ^[A-Za-z]: ]] && echo 'Windows' || echo 'Linux'
[[ '/usr/lib' =~ ^[A-Za-z]: ]] && echo 'Windows' || echo 'Linux'
Windows
Linux
ファイルシステム ext4 では C:\
のようなディレクトリ名を使用可能ですが、環境変数 PATH
等でコロン :
が区切り文字として使用されていることもあり、ディレクトリ名にコロン :
を使用することは避けるべきです。
(もし C:\
という名前のディレクトリに移動したければ、cd 'C:\'
の代わりに cd './C:\'
とすれば可能です。)
参考「命名規則 - ファイル、パス、名前空間の名前付け - Win32 apps | Microsoft Learn」
参考「ext4 - Wikipedia」
参考「PATH - Bash Reference Manual」
2.3. Linux の cd
コマンドの引数
Linux の cd
コマンドの引数はパスだけでなくオプションを伴うことがあります。
cd [-L|[-P [-e]] [-@]] [dir]
※ cd
コマンドの詳細は help cd
等を参照。
参考「cd - Bash Reference Manual」
ここでは最後の位置パラメータ "${@:$#}"
を分割し、Windows の絶対パスかどうかを確認します。
cd ~
と同じ意味で引数なしの cd
を使用する場合があるため、引数なしの場合は位置パラメータの確認をしないようにします。
※引数なしの cd
は cd ''
と意味が異なります。
cd -L
のように最後の位置パラメータがパスでなくオプションの場合も、最後の位置パラメータが Windows の絶対パスでないとみなせるため、問題なく処理出来ます。
参考「[シェル] 位置パラメータを配列のように扱う - Qiita」
3. おまけ: wslpath
コマンドでドライブ文字を含む相対パスを指定した場合の不具合について
Windows では「ドライブ文字を含む相対パス」が存在しますが、wslpath
コマンドで正しく変換されない上にエラー終了しないようです。
(「ドライブ文字を含む相対パス」が「コロン :
を含む相対パス」とみなされる?)
cd /mnt/c
wslpath 'C:' && echo 'OK' || echo 'NG'
C:
OK