理系学生日記

おまえはいつまで学生気分なのか

シェルスクリプトから direnv を利用する

ディレクトリごとに環境変数を切り替えたいというユースケースはよくありますが、それを実現してくれるのが direnv です。

ぼくもこの direnv を利用して、AWS アカウントごとのアクセスキーを切り替えたりしています。

direnv は通常、各シェルの cd の実行をフックする形で動きます。しかし、シェルスクリプトの中でこれを実現できない。どうやるものかと思っていたら、最終的には direnv export ${SHELL} を呼び出せば良いということに気付きました。

direnv のセットアップは eval $(direnv hook ${SHELL}) で実行します。direnv hook zsh の出力をみてみましょう。

$ direnv version
2.22.0
$ direnv hook zsh

_direnv_hook() {
  trap -- '' SIGINT;
  eval "$("/usr/local/bin/direnv" export zsh)";
  trap - SIGINT;
}
typeset -ag precmd_functions;
if [[ -z ${precmd_functions[(r)_direnv_hook]} ]]; then
  precmd_functions=( _direnv_hook ${precmd_functions[@]} )
fi
typeset -ag chpwd_functions;
if [[ -z ${chpwd_functions[(r)_direnv_hook]} ]]; then
  chpwd_functions=( _direnv_hook ${chpwd_functions[@]} )
fi

precmd_functions が出てきますが、これはプロンプト表示前を hook して実行される zsh の function 配列です。

このため、zsh だと _direnv_hook をディレクトリ変更都度に実行していることがわかります。 さらに、本質的な処理は /usr/local/bin/direnv export zsh のみであることもわかります。

結果として、シェルスクリプトで cd する際、cd の場合に以下のような function を実行すれば良いです。

function direnv_cd() {
    cd "$1"
    eval "$(direnv export bash)"
}

direnv_cd /path/to/destDir