
$PATH
現在の作業ディレクトリに応じて環境変数を変更したいと思います。
私が にいて/foo/bar/baz
、ディレクトリ/foo/node_modules/.bin
と があるとします。 可能なものをすべてに再帰的に/foo/bar/baz/node_modules/.bin
追加したいと思います。./node_modules/.bin
$PATH
しかし、cd
別のディレクトリ (など/foo/bar
) に移動すると、元のクリーンな状態$PATH
が復元され、再び再帰的に検索が開始されます./node_modules/.bin
。
(npm の問題追跡システムから自分の質問を解決したい:ローカルにインストールされたパッケージも PATH に追加できますか?)
注: 私は Mac を使用していますが、一般的な解決策に興味があります。
答え1
導入
私の理解が正しければ、またはその祖先のいずれか"$X/node_modules/.bin"
が$X
あるディレクトリを追加したいのですね。$PWD
この投稿の最後にあるスクリプトは、必要な動作を実現するはずです。必要なすべてのセッションでこれをソースする必要があります。ファイルに という名前を付ける場合はaugment_path.sh
、次の行を追加するだけで.bashrc
十分です。
source augment_path.sh
議論
garyjohn の基本的なアプローチは正しいと思いますが、彼はすべての先祖ではなくすべての子孫を検索しています。
変数$PROMPT_COMMAND
を使用すると、プロンプトが表示されるたびに実行されるコマンドを指定できます。$PROMPT_COMMAND_OLD
元のコマンド$PROMPT_COMMAND
を復元できるように変数を追加しました。
おそらく必要ではありませんが、$LAST_WD
ディレクトリが変更されていない場合にパスの再計算を回避するために、変数とテストを追加します。必要に応じて、次の 3 行をすべて削除できますLAST_WD
。
このaugment_path
関数は$PWD
上方からスキャンし、各祖先内のターゲット ディレクトリを検索し、見つかったディレクトリをパスに追加します。
これらはパスに順番に配置されるため、競合がある場合は最も深いディレクトリが優先されます。これが望ましい動作だと思います。そうでない場合は、変更してください。
PATH_ADDITION="$PATH_ADDITION:$resolved_target"
に
PATH_ADDITION="$resolved_target:$PATH_ADDITION"
ただし、これらのディレクトリはすべてパスの残りの部分よりも優先されます。パスの残りの部分を優先させたい場合は、次のように変更します。
PATH="$PATH_ADDITION:$RAW_PATH"
に
PATH="$RAW_PATH:$PATH_ADDITION"
脚本
RAW_PATH="$PATH"
LAST_WD=`pwd`
augment_path() {
target="node_modules/.bin"
if [ "$PWD" = "$LAST_WD" ]; then return 0; fi;
PATH_ADDITION=""
scandir="$PWD"
until [ "$scandir" = "" ]; do
resolved_target="$scandir"/"$target"
if [ -d "$resolved_target" ]; then
PATH_ADDITION="$PATH_ADDITION:$resolved_target"
fi
scandir="${scandir%/*}"
done
PATH="$PATH_ADDITION:$RAW_PATH"
LAST_WD=`pwd`
}
PROMPT_COMMAND_OLD="${PROMPT_COMMAND%; augment_path}"
PROMPT_COMMAND="$PROMPT_COMMAND_OLD; augment_path"
答え2
bashのPROMPT_COMMAND
:
PROMPT_COMMAND='[ -z "$X" ] && X=$PATH; PATH=$X:$(pwd)/node_modules/.bin'
そのコマンドはプロンプトが表示されるたびに実行されます。したがって、コマンドが終了するたびに変数PATH
が変更されます。最後に追加のディレクトリが追加されます。
現在の作業ディレクトリにディレクトリがない場合でも./node_modules/.bin
、パスは追加されます。しかし、これは問題ではありません。パスは検索されません (存在しないため)。
デモをご覧ください:
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$ PROMPT_COMMAND='[ -z "$X" ] && X=$PATH; PATH=$X:$(pwd)/node_modules/.bin'
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/node_modules/.bin
$ cd test
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/test/node_modules/.bin
$ cd /etc/
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/etc/node_modules/.bin
答え3
以下の内容を入力すれば、~/.bashrc
希望どおりの結果が得られると私は思います。
bash 環境変数がPROMPT_COMMAND
何らかのコマンドに設定されている場合、bash がプライマリプロンプトを表示する前にそのコマンドが実行されます。
以下のコードでは、PROMPT_COMMAND
は関数の名前 に設定されています。doit
その関数は、現在の作業ディレクトリが変更されたかどうかを確認し、変更された場合は最初に をPATH
元の値に設定し、次に という名前のサブディレクトリの存在を確認しますnode_modules/.bin
。そのサブディレクトリが存在する場合、関数はそのサブディレクトリの名前とその下にあるすべてのサブディレクトリの名前を に追加しますPATH
。
orig_path="$PATH"
prev_pwd=""
doit() {
if [ "$PWD" != "$prev_pwd" ]; then
PATH="$orig_path"
if [ -d "node_modules/.bin" ]; then
PATH="$PATH$(find $PWD/node_modules/.bin -type d -printf ':%p')"
# For POSIX compatibility (macOS or other), use:
# PATH="$PATH$(find $PWD/node_modules/.bin -type d -exec echo -n :{} \;)"
fi
prev_pwd="$PWD"
fi
}
PROMPT_COMMAND=doit