Posso alterar meu PATH dinamicamente com base no meu cwd?

Posso alterar meu PATH dinamicamente com base no meu cwd?

Gostaria de alterar minha $PATHvariável de ambiente dependendo do meu diretório de trabalho atual.

Digamos que estou dentro /foo/bar/baze tenho os diretórios /foo/node_modules/.bine /foo/bar/baz/node_modules/.bin. Eu gostaria de adicionar todos os possíveis ./node_modules/.binrecursivamente ao $PATH.

Mas quando cdentro em um diretório diferente (como /foo/bar), quero que meu original limpo $PATHseja restaurado e, em seguida, comece a procurar ./node_modules/.binrecursivamente novamente.

(Quero resolver minha própria pergunta no rastreador de problemas do npm:Também podemos adicionar pacotes instalados localmente ao PATH?)

Nota: estou em um Mac, mas estou interessado em uma solução geral.

Responder1

Introdução

Se bem entendi, você deseja adicionar quaisquer diretórios "$X/node_modules/.bin"onde $Xestá o $PWDou qualquer um de seus ancestrais.

O script no final deste post deve fornecer o comportamento que você deseja. Você precisa obtê-lo em todas as sessões onde desejar. Se você nomear o arquivo augment_path.sh, adicionar esta linha ao seu .bashrcdeverá ser suficiente:

source augment_path.sh

Discussão

Acho que garyjohn acertou a abordagem básica, mas ele está pesquisando todos os descendentes e não todos os ancestrais.

A $PROMPT_COMMANDvariável permite especificar um comando a ser executado cada vez que o prompt for exibido. Adicionei uma $PROMPT_COMMAND_OLDvariável para permitir que o original $PROMPT_COMMANDseja restaurado

Provavelmente não é necessário, mas para uma boa forma, adiciono uma $LAST_WDvariável e testo para evitar recalcular o caminho quando o diretório não foi alterado. Você pode remover todas as três linhas que contêm, LAST_WDse desejar.

A augment_pathfunção verifica de $PWDcima para baixo, procurando os diretórios de destino em cada ancestral e adicionando ao caminho os que encontrar.

  • Eles são colocados no caminho em ordem, portanto, o diretório mais profundo terá precedência se houver algum conflito. Presumo que este seja o comportamento desejado. Se não, mude

    PATH_ADDITION="$PATH_ADDITION:$resolved_target"
    

    para

    PATH_ADDITION="$resolved_target:$PATH_ADDITION"
    
  • No entanto, todos esses diretórios terão precedência sobre o resto do caminho. Se você quiser que o resto do caminho tenha precedência, altere:

    PATH="$PATH_ADDITION:$RAW_PATH"
    

    para

    PATH="$RAW_PATH:$PATH_ADDITION"
    

Roteiro

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"

Responder2

Você pode trabalhar com bashPROMPT_COMMAND:

PROMPT_COMMAND='[ -z "$X" ] && X=$PATH; PATH=$X:$(pwd)/node_modules/.bin'

Esse comando é executado sempre que o prompt aparece. Portanto, sempre que um comando termina, a PATHvariável é alterada. Um diretório adicional é adicionado ao final.

Se não houver nenhum diretório ./node_modules/.binno diretório de trabalho atual, o caminho será anexado de qualquer maneira. Mas isso não é um problema. Não é pesquisado (porque não existe).

Veja a demonstração:

$ 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

Responder3

Acho que colocar o seguinte em sua ~/.bashrcvontade fará o que você quiser.

Se a variável de ambiente bash PROMPT_COMMANDestiver definida para algum comando, esse comando será executado antes que o bash exiba o prompt principal.

No código abaixo, PROMPT_COMMANDestá definido como o nome de uma função, doit. Essa função verifica se o diretório de trabalho atual foi alterado e, em caso afirmativo, primeiro define PATHseu valor original e, em seguida, verifica a presença de um subdiretório chamado node_modules/.bin. Se esse subdiretório existir, a função anexa os nomes dele e de todos os subdiretórios abaixo dele a 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

informação relacionada