Mi chiedo dove debba essere aggiunto un nuovo percorso alla variabile d'ambiente PATH
. So che questo può essere realizzato modificando .bashrc
(ad esempio), ma non è chiaro come farlo.
Per di qua:
export PATH=~/opt/bin:$PATH
o questo?
export PATH=$PATH:~/opt/bin
PATH=$PATH:~/opt/bin
o
PATH=~/opt/bin:$PATH
a seconda che tu voglia aggiungere ~/opt/bin
alla 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/bin
o variazioni sull'ordinazione funzionano bene. Non inserire export
all'inizio della riga poiché presenta ulteriori complicazioni (vedi sotto in "Note su shell diverse da bash").
Se PATH
viene creato da molti componenti diversi, potresti finire con voci duplicate. Vedere Come aggiungere il percorso della home directory per essere scoperto da Unix quale comando? e Rimuovere le voci duplicate $ PATH con il comando awk per evitare di aggiungere duplicati o rimuoverli.
Alcune distribuzioni inseriscono automaticamente ~/bin
nel tuo PERCORSO se esiste, comunque.
Inserisci la riga per modificare PATH
in ~/.profile
o in ~/.bash_profile
se è quello che hai.
Nota che ~/.bash_rc
non viene letto da nessun programma e ~/.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_profile
se non ti interessano le shell diverse da bash). Vedi Qual è la differenza tra loro e quale dovrei usare?
Non inserirlo in /etc/environment
o ~/.pam_environment
: questi non sono file Shell, non puoi utilizzare sostituzioni come $PATH
lì dentro. In questi file, puoi solo sovrascrivere una variabile, non aggiungerla ad essa.
Non è necessario export
se 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 che PATH
sia già nell'ambiente e che contenga 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 dover assicurarti che PATH
non sia vuoto ed esportato: se PATH
non è ancora impostato , quindi qualcosa come PATH=$PATH:/some/directory
imposterà PATH
su :/some/directory
e il componente vuoto all'inizio indica la directory corrente (come .:/some/directory
).
if [ -z "${PATH-}" ]; then export PATH=/usr/local/bin:/usr/bin:/bin; fi
In bash, ksh e zsh, export
è una sintassi speciale, ed entrambi PATH=~/opt/bin:$PATH
e export PATH=~/opt/bin:$PATH
fai anche la cosa giusta. In altre shell in stile Bourne/POSIX come dash (che è /bin/sh
su molti sistemi), export
viene analizzato come un normale comando, il che implica due differenze:
~
viene analizzato solo all'inizio di una parola, tranne nelle assegnazioni (vedere Come aggiungere il percorso della home directory per essere scoperto da Unix quale comando? per i dettagli);$PATH
fuori dalle doppie virgolette si interrompe se PATH
contiene spazi bianchi o \[*?
.Quindi in gusci come trattino, imposta export PATH=~/opt/bin:$PATH
PATH
sulla stringa letterale ~/opt/bin/:
seguito dal valore di PATH
fino al primo spazio. PATH=~/opt/bin:$PATH
(un compito semplice) non richiede virgolette e fa la cosa giusta. Se vuoi usare export
in 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 PATH
per portabilità anche su Bourne Shell che non ha accettato export var=value
e non ha fatto l'espansione della tilde).
¹ Questo non era vero nelle shell Bourne (come nell'attuale Bourne Shell, non nelle moderne shell in stile POSIX), ma è molto improbabile che si incontrino conchiglie così vecchie in questi giorni.
Ad ogni modo funziona, ma non fanno la stessa cosa: gli elementi di PATH
sono controllati da sinistra a destra. Nel tuo primo esempio, eseguibili in ~/opt/bin
avrà la precedenza su quelle installate, ad esempio, in /usr/bin
, che può 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
, possono inserire, ad esempio, un ls
diverso, che probabilmente useresti invece di /bin/ls
senza accorgersene. Ora immagina lo stesso per ssh
o per il tuo browser o la tua scelta ... (Lo stesso vale tre volte per averlo inserito nel tuo percorso.)
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 compito non aggiunge solo
~/opt/node/bin
, ma anche l'interoPATH
precedentemente 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 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
Linux determina il percorso di ricerca eseguibile con $PATH
variabile d'ambiente. Per aggiungere directory/data/myscripts all'inizio di $PATH
variabile di ambiente, utilizzare 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:
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.sh
e, a causa dell'istruzione export, tutti i programmi chiamati da bash hanno l'alterato $PATH
variabile. 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 in Shell ed è necessario esportare $PATH
variabile d'ambiente.
Ulteriori informazioni qui
Da qualche tempo ho tenuto con me due funzioni pathadd
e pathrm
che aiutano ad aggiungere elementi al percorso senza la necessità di preoccuparsi delle duplicazioni.
pathadd
accetta un argomento a percorso singolo e un argomento facoltativo after
che, se fornito, verrà aggiunto a PATH
altrimenti 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 /baz/bat
è 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.
Non posso parlare per altre distribuzioni, ma Ubuntu ha un file,/etc/environment, che è il percorso di ricerca predefinito per tutti gli utenti. Dal momento che il mio computer è utilizzato solo da me, ho inserito tutte le directory che desidero nel mio percorso lì, a meno che non sia un'aggiunta temporanea che ho inserito in uno script.
Ci sono alcune situazioni in cui utilizza PATH=/a/b:$PATH
potrebbe essere considerato il modo "errato" di aggiungere un percorso a PATH
:
PATH
nella stessa forma.PATH
in una forma diversa (ovvero un alias dovuto all'utilizzo di symlink o ..
).PATH
quando si intende sovrascrivere altre voci in PATH
.Questa funzione (solo Bash) fa la "cosa giusta" nelle situazioni precedenti (con un'eccezione, vedi sotto), restituisce codici di errore e stampa messaggi Nice 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 a PATH
in altri modi, quindi se un alias non canonico per un percorso è in PATH
, questo aggiungerà un duplicato. Cercare di canonicalizzare i percorsi già in PATH
è una proposta rischiosa poiché un percorso relativo ha un significato ovvio quando viene passato a prepath
ma quando già nel percorso non sai quale fosse l'attuale directory di lavoro quando è stato aggiunto.
Per aggiungere un nuovo percorso alla variabile d'ambiente PATH
:
export PATH=$PATH:/new-path/
Per applicare questa modifica a ogni Shell che apri, aggiungila al file che Shell sorgente quando viene invocato. In diverse shell questo può essere:
per esempio.
# export PATH=$PATH:/root/learning/bin/
# source ~/.bashrc
# echo $PATH
Puoi vedere il percorso fornito nell'output sopra.
Per me (su Mac OS X 10.9.5), aggiungendo il nome del percorso (ad es. /mypathname
) al file /etc/paths
ha funzionato molto bene.
Prima di modificare, echo $PATH
ritorna:
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
Dopo aver modificato /etc/paths
e riavviando Shell, la variabile $ PATH viene aggiunta con /pathname
. Infatti, echo $PATH
ritorna:
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/mypathname
Quello che è successo è che /mypathname
è stato aggiunto al $PATH
variabile.
Ecco la mia soluzione:
PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '!x[$0]++' | sed "s/\(.*\).\{1\}/\1/")
Una fodera semplice e piacevole che non lascia un trascinamento :