わさっきhb

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

wsl+zshで,PATHの不要なパスを削除

 以前より,Windows Subsystem for Linux (wsl)でrubyを実行すると,次のような警告メッセージが出ることがありました.

/home/takehikom/.rbenv/versions/2.7.0-dev/lib/ruby/gems/2.7.0/gems/pry-0.12.2/lib/pry/pager.rb:150: warning: Insecure world writable dir /mnt/c/ProgramData in PATH, mode 040777

 「/mnt/c/ProgramDataのパーミッションがworld writableだから安全でないよ」という内容です.
 今朝はこの件の解決を試みました.まずは普段のシェル(zsh)で,環境変数PATHの値の調査です.

$ echo $PATH
/home/takehikom/.nodebrew/current/bin:/home/takehikom/.local/bin:/home/takehikom/.pyenv/shims:/home/takehikom/.pyenv/bin:/home/takehikom/.rbenv/shims:/home/takehikom/.rbenv/bin:/home/takehikom/bin:/home/takehikom/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/mnt/c/ProgramData/DockerDesktop/version-bin:/mnt/c/Program Files/Docker/Docker/Resources/bin:/mnt/c/WINDOWS/system32:/mnt/c/WINDOWS:/mnt/c/WINDOWS/System32/Wbem:/mnt/c/WINDOWS/System32/WindowsPowerShell/v1.0:/mnt/c/Program Files (x86)/PuTTY:/mnt/c/WINDOWS/System32/OpenSSH:/mnt/c/Users/takehikom/AppData/Local/Microsoft/WindowsApps:/mnt/c/Users/takehikom/AppData/Local/Programs/Microsoft VS Code/bin:/mnt/c/msys64/usr/bin:/snap/bin

 出力のうち主に前半は,残しておく必要がありますが,途中からの,DockerだとかWINDOWSだとか,Program Filesだとかを含むパスは,wsl+zshの実行に必要のないものばかりです./mnt/c/msys64/usr/binについても,そのディレクトリのexeファイルを,wsl+zshのほうで実行することはありません.
 ということで,不要なパスを削除するための,zsh用の関数を作ることにします.ちなみにPATHの不要なパスを削除に書いたpathpackは,現在使用しておらず,かわりに.zshrcに「typeset -U path cdpath fpath manpath」と書いて,重複する要素を削除しています.
 関数名はpathをeliminateするということでelimpathとし,その定義は,次のようになりました.

function elimpath () {
  local -a ary
  for p in $path
  do
    case $p in
      /mnt/* ) ;;
#      *WINDOWS* ) ;;
#      *Program* ) ;;
#      *AppData/Local* ) ;;
      * ) ary=($ary $p) ;;
    esac
  done
#  echo "BEFORE: $path"
#  echo "AFTER: $ary"
  PATH=$((for p in $ary; do echo $p; done) | paste -s -d ':' -)
}

 2つの連続するコメント行について,前者は,「WINDOWSを含む文字列を除外」「Programを…」「AppData/Localを…」と書いていたのですが,いろいろ実行しているうちに,「/mnt/から始まる文字列を除外」でいいことに気づきました.将来的に,個別に追加するかもしれないので,3行はコメントにしています.後者の#を取り除くと,削減の前後の内容を出力します.
 デバッグを行い*1,うまくいった状況で,関数実行後のPATHの値は,次のようになりました.

$ echo $PATH
/home/takehikom/.nodebrew/current/bin:/home/takehikom/.local/bin:/home/takehikom/.pyenv/shims:/home/takehikom/.pyenv/bin:/home/takehikom/.rbenv/shims:/home/takehikom/.rbenv/bin:/home/takehikom/bin:/home/takehikom/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

 上記の関数定義,そしてそれを即座に実行する「elimpath」の行を,wslのときだけ実行する,.zshrc*2のファイルに書き込んで,新規にzshを起動し,問題なく動作すること,そして「warning: Insecure world writable dir」を含む警告メッセージが出なくなることを,確認しました.

*1:当初はPATHへの代入のところを「path=$ary」と書いていたのですが,そうするとPATHの値は,パスの区切りがコロンではなく空白文字となってしまい,which rubyで実行パスが見つからなくなりました.

*2:今回作った関数は,bashではうまく動きません.主な理由は,配列の扱いがzshbashとで異なるためです.