Le voci duplicate in $ PATH sono un problema?


45

Provo bashrc di alcuni dei miei amici. Quindi finisco per avere voci duplicate nella mia variabile $ PATH. Non sono sicuro se questo sia il problema per l'avvio di comandi che richiedono molto tempo. Come funziona internamente $ PATH in bash? Avere più PERCORSI rallenta il mio tempo di avvio?




Risposte:


42

Avere più voci in $PATHnon rallenta direttamente l'avvio, ma rallenta ogni volta che si esegue per la prima volta un determinato comando in una sessione di shell (non tutte le volte che si esegue il comando, perché bash mantiene una cache). Il rallentamento è raramente percepibile se non si dispone di un file system particolarmente lento (ad esempio NFS, Samba o altri file system di rete o su Cygwin).

Le voci duplicate sono anche un po 'fastidiose quando rivedi $PATHvisivamente, devi guadare più cruft.

È abbastanza facile evitare di aggiungere voci duplicate.

case ":$PATH:" in
  *":$new_entry:"*) :;; # already there
  *) PATH="$new_entry:$PATH";; # or PATH="$PATH:$new_entry"
esac

Nota a margine: reperire lo script shell di qualcun altro significa eseguire il codice che ha scritto. In altre parole, stai dando ai tuoi amici l'accesso al tuo account ogni volta che lo desiderano.

Nota a margine: .bashrcnon è il posto giusto da impostare $PATHo qualsiasi altra variabile d'ambiente. È necessario impostare le variabili di ambiente ~/.profile. Vedi Quali file di installazione dovrebbero essere usati per impostare le variabili d'ambiente con bash? , Differenza tra .bashrc e .bash_profile .


8
+1: non posso sottolineare che "dare ai tuoi amici l'accesso al tuo account" abbastanza enfasi. Anche se non vi è alcun tentativo di farti del male, la loro sceneggiatura potrebbe essere proprio ciò di cui hanno bisogno e consumare comunque il tuo pranzo quando lo procedi.
risposta

Un possibile problema con questa soluzione è se $ new_entry è già la prima voce in PATH, ": $ new_entry:" non corrisponderà. Ho risolto questo problema nel mio profilo escludendo i due punti iniziali ":".
Jeff Bauer,

@JeffBauer Non vedo il problema. Uso case :$PATH:e non in case $PATHmodo che corrisponda anche se la voce è la prima o l'ultima.
Gilles 'SO- smetti di essere malvagio'

31

Ho visto persone ripulire i duplicati dalla loro variabile PATH usando awke qualcosa del genere:

PATH=$(printf "%s" "$PATH" | awk -v RS=':' '!a[$1]++ { if (NR > 1) printf RS; printf $1 }')

Potresti provare ad aggiungerlo al tuo bashrc e assicurarti di avere gli altri file da qualche parte prima di eseguirlo.

Un'alternativa sarebbe usare l'pathmerge utilità.

Per quanto riguarda il tuo problema di velocità, ciò non influirà in modo significativo sul tempo di avvio della shell ma potrebbe risparmiare un po 'di tempo facendo il completamento della scheda per i comandi, specialmente quando il comando non viene trovato nel percorso e fa ricerche ripetute attraverso lo stesso cartelle che lo cercano.

Una nota sulla sicurezza: dovresti davvero ascoltare gli avvisi di Gilles sulla sicurezza qui. Con l'approvvigionamento di un file di proprietà di un altro utente, si concede un passaggio gratuito a quegli utenti per eseguire il proprio codice come utente ogni volta che si avvia una shell. Se non ti fidi di quegli utenti con la tua password, non dovresti cercare i loro file shell.


6
Mi piace il monotono awk, ma stampa un ORS finale ":". Quindi l'ho modificato per leggerePATH=$(echo "$PATH" | awk -v RS=':' -v ORS=":" '!a[$1]++{if (NR > 1) printf ORS; printf $a[$1]}')
gkb0986,

Il trailing :non è solo un problema estetico. È lo stesso che aggiungere .al tuo percorso, che è potenzialmente pericoloso.
wisbucky,

Ho modificato la risposta per includere la correzione da gkb0986.
Tim Lesher,

@TimLesher Il motivo per cui non avevo mai modificato che in risposta è che non funziona per me .... e l'originale senza di esso funziona (incluso non lasciare un separatore finale. Non so quale sia la differenza .
Caleb

1
@ gkb0986 Questa soluzione non riesce ancora se il percorso contiene uno spazio di escape, come PATH = / bin: / foo \ bar: / usr / bin. Ho trovato una variante che evita questo su unix.stackexchange.com/a/124517/106102
maharvey67

13

Sulla base della risposta di @Gilles puoi avvolgerlo in una funzione per ridurre al minimo la digitazione:

function addToPATH {
  case ":$PATH:" in
    *":$1:"*) :;; # already there
    *) PATH="$1:$PATH";; # or PATH="$PATH:$1"
  esac
}

addToPATH /Applications/AIRSDK_Compiler/bin
addToPATH ~/.local/lib/npm/bin

1
La risposta più utilizzabile (di alto livello, forse).
ijoseph,

3

$PATHViene eseguita solo la prima corrispondenza in , quindi eventuali voci successive non vengono elaborate successivamente. Ecco perché a volte dovresti modificare l'ordine delle voci nel tuo $PATHper far sì che il tuo ambiente si comporti come previsto.

Per rispondere alla tua domanda: questa non dovrebbe essere la causa dell'avvio lento.


1
Ma ci vuole più tempo quando scrivo un comando che non esiste. Cercherà due volte nella stessa cartella il comando.
balki,

@balki Intendi completare un comando con TAB? In tal caso, è necessario verificare se la definizione completa non è simile complete -c which -a. È necessario eliminare il -aparametro. È possibile verificare che con il comando: complete | grep which.
Rajish,

Potrebbe essere ancora un problema se cerca nella stessa directory in cui non si trova più volte prima di trovarla.
Casuale 832

-1

Per evitare voci duplicate nel mio PERCORSO, ho dovuto inserire quanto segue in ENTRAMBI ~ / .bash_profile e ~ / .bashrc:

PATH=$(echo $(sed 's/:/\n/g' <<< $PATH | sort | uniq) | sed -e 's/\s/':'/g')

Lo svantaggio principale è che ordina le voci PATH, ma penso di poter convivere con quello.


L'ordine della ricerca PATH è piuttosto importante.
Steven Shaw,
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.