Come aggiungere correttamente un percorso a PATH?


922

Mi chiedo dove debba essere aggiunto un nuovo percorso alla PATHvariabile d'ambiente. So che questo può essere realizzato modificando .bashrc(per esempio), ma non è chiaro come farlo.

Per di qua:

export PATH=~/opt/bin:$PATH

o questo?

export PATH=$PATH:~/opt/bin

printf '\ nPATH = $ PATH: "percorso da aggiungere" \ nexport PATH \ n' >> ~ / .bashrc
Sudoer


Se sono già stati aggiunti alcuni percorsi, ad es PATH=$PATH:$HOME/.local/bin:$HOME/bin. Un altro può essere aggiunto separando con un: ad es PATH=$PATH:$HOME/.local/bin:$HOME/bin:/home/ec2-user/pear/bin.
Sandeepan Nath,

2
Queste risposte funzionano per tutti i gusti di Linux?
Ungeheuer,

Risposte:


1032

Le cose semplici

PATH=$PATH:~/opt/bin

o

PATH=~/opt/bin:$PATH

a seconda che si desideri aggiungere ~/opt/binalla fine (da cercare dopo tutte le altre directory, nel caso in cui vi sia un programma con lo stesso nome in più directory) o all'inizio (da cercare prima di tutte le altre directory).

È possibile aggiungere più voci contemporaneamente. PATH=$PATH:~/opt/bin:~/opt/node/bino variazioni sull'ordinazione funzionano bene. Non inserire exportall'inizio della riga in quanto presenta ulteriori complicazioni (vedi sotto in "Note su shell diverse da bash").

Se il tuo PATHviene creato da molti componenti diversi, potresti finire con voci duplicate. Vedi Come aggiungere il percorso della home directory per essere scoperto da Unix quale comando? e Rimuovi voci duplicate $ PATH con il comando awk per evitare di aggiungere duplicati o rimuoverli.

A ~/binproposito, alcune distribuzioni inseriscono automaticamente il tuo PERCORSO.

Dove metterlo

Mettere la linea di modificare PATHin ~/.profile, o in ~/.bash_profileSe questo è quello che hai.

Nota che ~/.bash_rcnon viene letto da nessun programma ed ~/.bashrcè il file di configurazione delle istanze interattive di bash. Non è necessario definire le variabili di ambiente in ~/.bashrc. Il posto giusto per definire variabili d'ambiente come PATHè ~/.profile(o ~/.bash_profilese non ti interessano le shell diverse da bash). Vedi Qual è la differenza tra loro e quale dovrei usare?

Non inserirlo /etc/environmento ~/.pam_environment: questi non sono file shell, non è possibile utilizzare sostituzioni come quelle $PATHpresenti. In questi file, puoi solo sovrascrivere una variabile, non aggiungerla ad essa.

Potenziali complicazioni in alcuni script di sistema

Non è necessario exportse la variabile è già nell'ambiente: qualsiasi modifica del valore della variabile si riflette nell'ambiente.¹ PATHè praticamente sempre nell'ambiente; tutti i sistemi unix lo hanno impostato molto presto (di solito nel primo processo, in effetti).

Al momento dell'accesso, puoi fare affidamento sul fatto di PATHessere già nell'ambiente e di contenere già alcune directory di sistema. Se stai scrivendo uno script che potrebbe essere eseguito in anticipo durante l'impostazione di un qualche tipo di ambiente virtuale, potresti aver bisogno di assicurarti che PATHnon sia vuoto ed esportato: se PATHè ancora non impostato, allora qualcosa di simile PATH=$PATH:/some/directorysarebbe impostato PATHsu :/some/directorye il componente vuoto all'inizio significa l'attuale directory (come .:/some/directory).

if [ -z "${PATH-}" ]; then export PATH=/usr/local/bin:/usr/bin:/bin; fi

Note su conchiglie diverse da bash

In bash, ksh e zsh, exportc'è una sintassi speciale, ed entrambi PATH=~/opt/bin:$PATHe export PATH=~/opt/bin:$PATHfanno anche la cosa giusta. In altre shell in stile Bourne / POSIX come dash (che si trova /bin/shsu molti sistemi), exportviene analizzato come un normale comando, il che implica due differenze:

Quindi nelle shell come dash, export PATH=~/opt/bin:$PATHimposta PATHla stringa letterale ~/opt/bin/:seguita dal valore PATHfino al primo spazio. PATH=~/opt/bin:$PATH(un compito semplice) non richiede preventivi e fa la cosa giusta. Se vuoi usarlo exportin uno script portatile, devi scrivere export PATH="$HOME/opt/bin:$PATH", o PATH=~/opt/bin:$PATH; export PATH(o PATH=$HOME/opt/bin:$PATH; export PATHper la portabilità anche alla shell Bourne che non ha accettato export var=valuee non ha fatto l'espansione della tilde).

¹ Questo non era vero nelle shell Bourne (come nell'attuale shell Bourne, non nelle moderne shell in stile POSIX), ma è molto improbabile che si incontrino conchiglie così vecchie in questi giorni.


Non riesco ancora a capire la complicazione con l'esportazione. puoi per favore semplificarlo?
priojeet priyom

@priojeetpriyom Semplice spiegazione: non è necessario export.
Gilles,

Grazie per questa risposta, perfettamente dettagliata. Dici " Non dovresti definire le variabili d'ambiente in ~ / .bashrc ", ma sfortunatamente il 100% dei programmi che ho installato sul mio sistema che modifica il percorso (FZF e Rust's Cargo) modifica il percorso in .bashrc. Presumo perché anche FZF è scritto in Rust, segue il modello di Rust.
icc97,

83

Ad ogni modo funziona, ma non fanno la stessa cosa: gli elementi di PATHsono controllati da sinistra a destra. Nel tuo primo esempio, gli eseguibili in ~/opt/binavranno la precedenza su quelli installati, ad esempio, in /usr/bin, che possono essere o meno ciò che desideri.

In particolare, dal punto di vista della sicurezza, è pericoloso aggiungere percorsi in primo piano, perché se qualcuno può ottenere l'accesso in scrittura al tuo ~/opt/bin, può inserire, ad esempio, un diverso lslì dentro, che probabilmente useresti invece di /bin/lssenza accorgersene. Ora immagina lo stesso per il sshtuo browser o la tua scelta ... (Lo stesso vale tre volte per averlo messo nel tuo percorso.)


6
Ma se vuoi avere la tua versione personalizzata di ls, devi metterla in una directory prima di /bin.
Barmar,

16
o alias ls = myls
waltinator,

37

Sono confuso dalla domanda 2 (poiché rimosso dalla domanda poiché era dovuto a un problema non correlato):

Qual è un modo praticabile per aggiungere più percorsi su linee diverse? Inizialmente pensavo che questo potesse fare il trucco:

export PATH=$PATH:~/opt/bin
export PATH=$PATH:~/opt/node/bin

ma non perché il secondo incarico non solo accoda ~/opt/node/bin, ma anche l'intero PATHprecedentemente assegnato.

Questa è una possibile soluzione alternativa:

export PATH=$PATH:~/opt/bin:~/opt/node/bin

ma per leggibilità preferirei avere un compito per un percorso.

Se dici

PATH=~/opt/bin

questo è tutto ciò che sarà nel tuo PERCORSO. PERCORSO è solo una variabile d'ambiente e se si desidera aggiungere al PERCORSO, è necessario ricostruire la variabile con esattamente il contenuto desiderato. Cioè, quello che dai come esempio alla domanda 2 è esattamente quello che vuoi fare, a meno che non mi manchi completamente il punto della domanda.

Uso entrambi i moduli nel mio codice. Ho un profilo generico che installo su ogni macchina su cui lavoro che assomiglia a questo, per adattarsi alle directory potenzialmente mancanti:

export PATH=/opt/bin:/usr/local/bin:/usr/contrib/bin:/bin:/usr/bin:/usr/sbin:/usr/bin/X11
# add optional items to the path
for bindir in $HOME/local/bin $HOME/bin; do
    if [ -d $bindir ]; then
        PATH=$PATH:${bindir}
    fi
done

2
Hai ragione sull'esempio della domanda 2, funziona. Un altro problema relativo al PERCORSO sul mio sistema mi ha confuso. Scusa per quello.
Paolo,

26

Il modo a prova di proiettile di aggiungere / preparare

Ci sono molte considerazioni coinvolte nella scelta di aggiungere rispetto a anteporre. Molti di essi sono trattati in altre risposte, quindi non li ripeterò qui.

Un punto importante è che, anche se gli script di sistema non lo utilizzano (mi chiedo perché) * 1 , il modo a prova di proiettile per aggiungere un percorso (ad esempio, $HOME/bin) alla variabile di ambiente PATH è

PATH="${PATH:+${PATH}:}$HOME/bin"

per aggiungere (invece di PATH="$PATH:$HOME/bin") e

PATH="$HOME/bin${PATH:+:${PATH}}"

per anteporre (anziché PATH="$HOME/bin:$PATH")

Ciò evita i due spuri di testa / coda quando $PATHè inizialmente vuoto, che può avere effetti collaterali indesiderati e può diventare un incubo , sfuggente da trovare ( questa risposta tratta brevemente il caso awk).

Spiegazione (dall'espansione dei parametri della shell ):

${parameter:+word}

Se parameterè null o non impostato, non viene sostituito nulla, altrimenti viene sostituita l'espansione di word.

Pertanto, ${PATH:+${PATH}:}viene espanso a: 1) nulla, se PATHè nullo o non impostato, 2) ${PATH}:, se PATHimpostato.

Nota : questo è per bash.


* 1 Ho appena scoperto che script come devtoolset-6/enableeffettivamente usano questo,

$ cat /opt/rh/devtoolset-6/enable
# General environment variables
export PATH=/opt/rh/devtoolset-6/root/usr/bin${PATH:+:${PATH}}
...

24

Linux determina il percorso di ricerca eseguibile con la $PATHvariabile di ambiente. Per aggiungere directory / data / myscripts all'inizio della $PATHvariabile d'ambiente, usare quanto segue:

PATH=/data/myscripts:$PATH

Per aggiungere quella directory alla fine del percorso, utilizzare il seguente comando:

PATH=$PATH:/data/myscripts

Ma i precedenti non sono sufficienti perché quando si imposta una variabile di ambiente all'interno di uno script, tale modifica è effettiva solo all'interno dello script. Esistono solo due modi per aggirare questa limitazione:

  • Se all'interno dello script, la variabile d'ambiente viene esportata, è efficace all'interno di tutti i programmi richiamati dallo script. Si noti che non è efficace all'interno del programma che ha chiamato lo script.
  • Se il programma che chiama lo script lo fa per inclusione invece di chiamare, qualsiasi modifica dell'ambiente nello script è efficace all'interno del programma chiamante. Tale inclusione può essere effettuata con il comando punto o il comando sorgente.

Esempi:

$HOME/myscript.sh
source $HOME/myscript.sh

Inclusione fondamentalmente incorpora lo script "chiamato" nello script "chiamante". È come un #include in C. Quindi è efficace all'interno dello script o del programma "chiamante". Ma, naturalmente, non è efficace in alcun programma o script chiamato dal programma chiamante. Per renderlo efficace lungo tutta la catena di chiamate, è necessario seguire l'impostazione della variabile di ambiente con un comando di esportazione.

Ad esempio, il programma shell bash incorpora il contenuto del file .bash_profile per inclusione. Inserire le seguenti 2 righe in .bash_profile:

PATH=$PATH:/data/myscripts
export PATH

inserisce efficacemente quelle 2 righe di codice nel programma bash. Quindi all'interno di bash, la variabile $ PATH include $HOME/myscript.she, a causa dell'istruzione export, tutti i programmi chiamati da bash hanno la $PATHvariabile modificata . E poiché tutti i programmi eseguiti da un prompt di bash sono chiamati da bash, il nuovo percorso è in vigore per tutto ciò che si esegue dal prompt di bash.

La linea di fondo è che per aggiungere una nuova directory al percorso, è necessario aggiungere o anteporre la directory alla variabile di ambiente $ PATH all'interno di uno script incluso nella shell ed è necessario esportare la $PATHvariabile di ambiente.

Maggiori informazioni qui


19

Da qualche tempo ho tenuto con me due funzioni pathadde pathrmche aiutano ad aggiungere elementi al percorso senza la necessità di preoccuparsi delle duplicazioni.

pathaddaccetta un argomento a percorso singolo e un afterargomento facoltativo che, se fornito, verrà aggiunto al PATHcontrario, lo antepone.

In quasi tutte le situazioni, se stai aggiungendo al percorso, probabilmente vorrai sovrascrivere qualsiasi cosa già presente nel percorso, motivo per cui scelgo di anteporre per impostazione predefinita.

pathadd() {
    newelement=${1%/}
    if [ -d "$1" ] && ! echo $PATH | grep -E -q "(^|:)$newelement($|:)" ; then
        if [ "$2" = "after" ] ; then
            PATH="$PATH:$newelement"
        else
            PATH="$newelement:$PATH"
        fi
    fi
}

pathrm() {
    PATH="$(echo $PATH | sed -e "s;\(^\|:\)${1%/}\(:\|\$\);\1\2;g" -e 's;^:\|:$;;g' -e 's;::;:;g')"
}

Inseriscili in qualsiasi script che desideri modificare l'ambiente PATH e ora puoi farlo.

pathadd "/foo/bar"
pathadd "/baz/bat" after
export PATH

Sei sicuro di non aggiungere al percorso se è già lì. Se ora vuoi assicurarti che /baz/batsia all'inizio.

pathrm "/baz/bat"
pathadd "/baz/bat"
export PATH

Ora qualsiasi percorso può essere spostato in primo piano se è già nel percorso senza raddoppiare.


Approccio correlato e più pulito per verificare la presenza di una directory nel PERCORSO: unix.stackexchange.com/a/32054/135943
Wildcard

9

Non posso parlare per altre distribuzioni, ma Ubuntu ha un file, / etc / environment, che è il percorso di ricerca predefinito per tutti gli utenti. Dato che il mio computer è usato solo da me, ho inserito tutte le directory che desidero sul mio percorso, a meno che non sia un'aggiunta temporanea che ho inserito in uno script.


6

Ci sono alcune situazioni in cui l'utilizzo PATH=/a/b:$PATHpotrebbe essere considerato il modo "errato" di aggiungere un percorso a PATH:

  1. Aggiunta di un percorso che in realtà non è una directory.
  2. Aggiunta di un percorso già presente PATHnella stessa forma.
  3. Aggiunta di un percorso relativo (poiché la directory effettiva cercata cambierebbe quando si cambia la directory di lavoro corrente).
  4. Aggiunta di un percorso che è già in PATHuna forma diversa (ad esempio un alias dovuto all'utilizzo di symlink o ..).
  5. Se si evita di fare 4, non spostare il percorso in primo piano PATHquando si intende sovrascrivere altre voci PATH.

Questa funzione (solo Bash) fa la "cosa giusta" nelle situazioni sopra (con un'eccezione, vedi sotto), restituisce codici di errore e stampa bei messaggi per gli umani. I codici di errore e i messaggi possono essere disabilitati quando non sono desiderati.

prepath() {
    local usage="\
Usage: prepath [-f] [-n] [-q] DIR
  -f Force dir to front of path even if already in path
  -n Nonexistent dirs do not return error status
  -q Quiet mode"

    local tofront=false errcode=1 qecho=echo
    while true; do case "$1" in
        -f)     tofront=true;       shift;;
        -n)     errcode=0;          shift;;
        -q)     qecho=':';          shift;;
        *)      break;;
    esac; done
    # Bad params always produce message and error code
    [[ -z $1 ]] && { echo 1>&2 "$usage"; return 1; }

    [[ -d $1 ]] || { $qecho 1>&2 "$1 is not a directory."; return $errcode; }
    dir="$(command cd "$1"; pwd -P)"
    if [[ :$PATH: =~ :$dir: ]]; then
        $tofront || { $qecho 1>&2 "$dir already in path."; return 0; }
        PATH="${PATH#$dir:}"        # remove if at start
        PATH="${PATH%:$dir}"        # remove if at end
        PATH="${PATH//:$dir:/:}"    # remove if in middle
    fi
    PATH="$dir:$PATH"
}

L'eccezione è che questa funzione non può canonicalizzare i percorsi aggiunti PATHtramite altri mezzi, quindi se è presente un alias non canonico per un percorso PATH, questo aggiungerà un duplicato. Cercare di canonicalizzare i percorsi già presenti PATHè una proposta rischiosa poiché un percorso relativo ha un significato ovvio quando viene passato prepathma quando già nel percorso non si conosce quale sia la directory di lavoro corrente quando è stata aggiunta.


per quanto riguarda i percorsi relativi: che dire di avere un interruttore '-r', che aggiungerebbe il percorso senza renderlo assoluto prima e che lo cercherebbe anche come assoluto prima di aggiungerlo? Se questo fosse uno script, si potrebbe usarlo in altre shell. C'è qualche vantaggio di averlo come funzione? bel codice!
hoijui,

1
@hoijui Deve essere una funzione perché sta modificando l'ambiente attuale. Se fosse uno script, modificherebbe l'ambiente del sottoprocesso che esegue lo script e, quando lo script uscisse, avresti lo stesso $PATHdi prima. Per quanto riguarda -r, no, penso che i percorsi relativi $PATHsiano troppo inaffidabili e strani (il tuo percorso cambia ogni volta che tu cd!) Per voler supportare qualcosa del genere in uno strumento generale.
Curt J. Sampson,

5

Per me (su Mac OS X 10.9.5), l'aggiunta del nome del percorso (ad es. /mypathname) Al file ha /etc/pathsfunzionato molto bene.

Prima della modifica, echo $PATHrestituisce:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

Dopo aver modificato /etc/pathse riavviato la shell, viene aggiunta la variabile $ PATH /pathname. Infatti, echo $PATHrestituisce:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/mypathname

Quello che è successo è /mypathnamestato aggiunto alla $PATHvariabile.


3
Meglio aggiungere un file alla directory /etc/paths.d che modificare il file / etc / percorsi stesso.
risposta

4

Per aggiungere un nuovo percorso alla PATHvariabile d'ambiente:

export PATH=$PATH:/new-path/

Per questo cambiamento da applicare ad ogni conchiglia che si apre, aggiungerlo al file che la shell fonte quando viene richiamato. In diverse shell questo può essere:

  • Bash Shell: ~ / .bash_profile, ~ / .bashrc o profilo
  • Korn Shell: ~ / .kshrc o .profile
  • Z Shell: ~ / .zshrc o .zprofile

per esempio

# export PATH=$PATH:/root/learning/bin/
# source ~/.bashrc
# echo $PATH

Puoi vedere il percorso fornito nell'output sopra.


4

Ecco la mia soluzione:

PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '!x[$0]++' | sed "s/\(.*\).\{1\}/\1/")

Una bella fodera facile che non lascia tracce :


1
-bash: awk: nessun file o directory simile -bash: sed: nessun file o directory
simile

1
@davidcondrey - awk e sed sono comandi esterni molto comuni. Questa risposta fornisce un modo puro di ottenere lo stesso, quindi funziona anche nei casi in cui awk e / o sed non sono presenti (o le loro rispettive directory non sono sulla strada!)
sancho.s
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.