내 cwd에 따라 PATH를 동적으로 변경할 수 있나요?

내 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을 사용하고 있지만 일반적인 솔루션에 관심이 있습니다.

답변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변수를 추가하고 디렉터리가 변경되지 않았을 때 경로를 다시 계산하지 않도록 테스트합니다. 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

관련 정보