web-dev-qa-db-ja.com

cwdに基づいてPATHを動的に変更できますか?

現在の作業ディレクトリに応じて、$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を使用していますが、一般的な解決策に興味があります。

5
Pipo

前書き

私があなたを正しく理解している場合は、ディレクトリ"$X/node_modules/.bin"を追加します。ここで、$X$PWDまたはその祖先のいずれかです。

この投稿の最後にあるスクリプトは、必要な動作を提供するはずです。あなたはそれを望むすべてのセッションでそれを調達する必要があります。ファイルにaugment_path.shという名前を付ける場合は、この行を.bashrcに追加するだけで十分です。

source augment_path.sh

討論

Garyjohnは基本的なアプローチを正しく持っていると思いますが、彼はすべての祖先ではなく、すべての子孫を検索しています。

$Prompt_COMMAND変数を使用すると、プロンプトが表示されるたびに実行されるコマンドを指定できます。元の$Prompt_COMMAND_OLDを復元できるように$Prompt_COMMAND変数を追加しました

おそらく必要ではありませんが、適切な形式にするために、$LAST_WD変数を追加し、ディレクトリが変更されていないときにパスが再計算されないようにテストします。必要に応じて、LAST_WDを含む3行すべてを削除できます。

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"
3
pyrocrasty

以下を~/.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
1
garyjohn

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
0
chaos