Un modo più comodo per modificare un lungo $ PATH?


35

Voglio aggiungere, in ~ / .bashrc, alcune directory al mio $ PATH.

Il mio $ PATH è piuttosto lungo, quindi è un po 'difficile vedere quali directory contiene e in quale ordine.

So che posso modificare il mio ~ / .bashrc per essere:

PATH=$PATH:/some/dir
PATH=$PATH:/another/dir:/yet/another
PATH=$PATH:/and/another
...

renderebbe più facile la lettura. Ma mi chiedevo se negli ultimi anni Bash ha acquisito una sintassi che rende più facile specificare un lungo PERCORSO. Ad esempio, sto fantasticando su una sintassi simile a:

PATH=:((
  /some/dir
  /another/dir
  /yet/another
  /and/another
  ...
))

Io so come sintassi non è valida. Mi chiedevo se c'è qualcosa di così facile. È lì?


Il tutorial tradizionale per impostare il percorso via PATH=foo:$PATHsembra sbagliato perché mantenere la crescita ogni volta source ~/.bashrce anche exec bashnon posso fare in quanto la $PATHè export.
林果 皞

Risposte:


25

Uso una serie di funzioni utili per anteporre o aggiungere un percorso a una variabile. Le funzioni sono disponibili nel tarball di distribuzione di Bash in un file contrib chiamato "pathfuncs".

  • add_path aggiungerà la voce alla fine della variabile PATH
  • pre_path aggiungerà la voce all'inizio della variabile PATH
  • del_path rimuoverà la voce dalla variabile PATH, ovunque si trovi

Se si specifica una variabile come secondo argomento, verrà utilizzata quella invece di PATH.

Per comodità, eccoli:

# is $1 missing from $2 (or PATH) ?
no_path() {
    eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac"
}
# if $1 exists and is not in path, append it
add_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1"
}
# if $1 exists and is not in path, prepend it
pre_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}"
}
# if $1 is in path, remove it
del_path () {
  no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: |
    sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"`
}

Se li aggiungi al tuo file di avvio di bash, puoi aggiungere al tuo PERCORSO in questo modo:

pre_path $HOME/bin
add_path /sbin
add_path /usr/sbin

Oppure specifica una variabile diversa:

pre_path $HOME/man MANPATH
pre_path $HOME/share/man MANPATH
add_path /usr/local/man MANPATH
add_path /usr/share/man MANPATH

Uso questo metodo nei miei file rc mettendo prima i percorsi_precedenti e il percorso_aggiunti secondo. Rende tutti i miei cambiamenti di percorso facili da capire a colpo d'occhio. Un altro vantaggio è che le righe sono abbastanza corte da poter aggiungere un commento finale su una riga, se necessario.

E poiché si tratta di funzioni, è possibile utilizzarle in modo interattivo dalla riga di comando, ad esempio dicendo add_path $(pwd)di aggiungere la directory corrente al percorso.


Grazie. Ho controllato il tuo codice e funziona. Sorprendentemente, ho anche trovato un uso per del_path (A "." Si insinua nel mio PERCORSO in alcune situazioni, il diavolo sa da dove, e così ho fatto del_path .).
Niccolò M.

Ciao. è possibile procurarsi (includere) questo pathfunc dallo script bashrc o dovrei copiarli / incollarli lì?
Cristiano,

@Cristiano Funzionerà entrambi. Dipende davvero da te.
Starfish,

11

OK, ho capito la seguente soluzione, che penso sia elegante (per quanto riguarda la sintassi della shell). Utilizza la sintassi dell'array di Bash e anche un modo pulito per unire gli elementi:

paths=(
  /some/dir
  /another/dir
  '/another/dir with spaces in it'
  /yet/another
  /and/another
  /end
)
paths_joined=$( IFS=: ; echo "${paths[*]}" )

PATH=$paths_joined:$PATH

METTERE IN GUARDIA!

Si scopre che questa soluzione ha un problema : a differenza delle soluzioni di @terdon e @Starfish, non controlla prima se i percorsi sono già in PATH. Quindi, poiché voglio mettere questo codice in ~ / .bashrc (e non in ~ / .profile), i percorsi duplicati si insinueranno nel PERCORSO. Quindi non usare questa soluzione (a meno che non la metti in ~ / .profile (o, meglio, ~ / .bash_profile in quanto ha una sintassi specifica di Bash)).


1
Molto bella. Puoi per favore accettare una risposta in modo che gli altri non vengano qui per offrire una soluzione quando ne hai già trovata una? Grazie
Basic

I percorsi duplicati non sono davvero un problema. È altamente improbabile che tu abbia aggiunto abbastanza directory per PATHcausare effettivamente problemi di prestazioni (soprattutto perché la shell memorizza con successo ricerche).
Chepner,

5

Uso la funzione di seguito nel mio ~/.bashrc. È qualcosa che ho ricevuto da un amministratore di sistema nel mio vecchio laboratorio, ma non credo che li abbia scritti. Aggiungi queste righe al tuo~/.profile o ~/.bashrc:

pathmunge () {
        if ! echo $PATH | /bin/grep -Eq "(^|:)$1($|:)" ; then
           if [ "$2" = "after" ] ; then
              PATH=$PATH:$1
           else
              PATH=$1:$PATH
           fi
        fi
}

Questo ha vari vantaggi:

  • Aggiunta di nuove directory a $PATH è banale: pathmunge /foo/bar;
  • Evita voci duplicate;
  • Puoi scegliere se aggiungere una nuova voce all'inizio ( pathmunge /foo/baro alla fine ( pathmunge /foo/bardopo) di $PATH.

Il file di inizializzazione della shell conterrebbe quindi qualcosa del tipo:

pathmunge /some/dir
pathmunge /another/dir
pathmunge '/another/dir with spaces in it'
pathmunge /yet/another
pathmunge /and/another
pathmunge /end

Grazie. Ma sceglierò la soluzione di @ Starfish perché non si genera grep.
Niccolò M.

2
@NiccoloM. nessun problema, accetta quello che preferisci. Fai attenzione con l'approccio delle stelle marine, ma eseguirà un codice arbitrario in evalmodo da poter causare alcuni seri danni se lo esegui con l'argomento sbagliato.
terdon,

Nota che esiste una funzione più veloce in redhat per farlo senza comando esterno grep, vedi bugzilla.redhat.com/show_bug.cgi?id=544652#c7
林果 皞

4

Voglio aggiungere, in ~ / .bashrc, alcune directory al mio $ PATH.

Uso quanto segue in Cygwin. Dovrebbe funzionare in altre versioni di bash. Puoi rimuovere il unset PATHda costruire sul tuo attuale PATH(se lo fai potresti dover capire come aggiungere :correttamente i separatori).

Nota:

  • Una volta avevo questa funzionalità in una bashfunzione ma l'ho persa dopo un crash del disco.

Nel mio .bash_profile:

# Build up the path using the directories in ~/.path_elements
unset PATH
while read line; do 
  PATH="${PATH}$line"; 
done < ~/.path_elements

...

# Add current directory to path
export PATH=".:${PATH}"

In ~/.path_elements:

/home/DavidPostill/bin:
/usr/local/bin:
/usr/bin:
/c/Windows/system32:
/c/Windows

Grazie. La tua risposta mi ha ispirato a lavorare su una soluzione simile. (Per i miei gusti, la memorizzazione dei percorsi in un file separato è un problema.)
Niccolò M.

1

Lo uso nel mio .bashrc (e anche nel mio .zshrc, poiché in genere uso zsh dove disponibile invece di bash). Certo, mi richiede di aggiungere manualmente le directory, ma un vantaggio è che mentre lo aggiorno, posso continuare a copiarlo su nuovi server e non preoccuparmi del PERCORSO su un nuovo server creato con directory che non esistono lì.

##
## SENTIERO
##
## Invece di limitarci a ostruire il nostro PERCORSO con directory che potrebbero
## non essere appropriato per questo server, cerca di essere intelligente su ciò che aggiungiamo
##
PATH = / usr / local / sbin: / usr / local / bin: / usr / sbin: / usr / bin: / sbin: / bin
[-d / cs / sbin] && PATH = / cs / sbin: $ PATH
[-d / cs / bin] && PATH = / cs / bin: $ PATH
[-d / usr / ucb] && PATH = $ PATH: / usr / ucb
[-d / usr / ccs / bin] && PATH = $ PATH: / usr / ccs / bin
[-d / usr / local / ssl / bin] && PATH = $ PATH: / usr / local / ssl / bin
[-d / usr / krb5 / bin] && PATH = $ PATH: / usr / krb5 / bin
[-d / usr / krb5 / sbin] && PATH = $ PATH: / usr / krb5 / sbin
[-d / usr / kerberos / sbin] && PATH = $ PATH: / usr / kerberos / sbin
[-d / usr / kerberos / bin] && PATH = $ PATH: / usr / kerberos / bin
[-d /cs/local/jdk1.5.0/bin] && PATH = $ PATH: /cs/local/jdk1.5.0/bin
[-d /usr/java/jre1.5.0_02/bin] && PATH = $ PATH: /usr/java/jre1.5.0_02/man
[-d /usr/java1.2/bin] && PATH = $ PATH: /usr/java1.2/bin
[-d /cs/local/perl5.8.0/bin] && PATH = $ PATH: /cs/local/perl5.8.0/bin
[-d / usr / perl5 / bin] && PATH = $ PATH: / usr / perl5 / bin
[-d / usr / X11R6 / bin] && PATH = $ PATH: / usr / X11R6 / bin
[-d / etc / X11] && PATH = $ PATH: / etc / X11
[-d / opt / sfw / bin] && PATH = $ PATH: / opt / sfw / bin
[-d / usr / local / apache / bin] && PATH = $ PATH: / usr / local / apache / bin
[-d / usr / apache / bin] && PATH = $ PATH: / usr / apache / bin
[-d / cs / admin / bin] && PATH = $ PATH: / cs / admin / bin
[-d / usr / openwin / bin] && PATH = $ PATH: / usr / openwin / bin
[-d / usr / xpg4 / bin] && PATH = $ PATH: / usr / xpg4 / bin
[-d / usr / dt / bin] && PATH = $ PATH: / usr / dt / bin

Faccio la stessa cosa per il mio MANPATH:

##
## MANPATH
##
## Invece di limitare a ostruire il nostro MANPATH con directory che potrebbero
## non essere appropriato per questo server, cerca di essere intelligente su ciò che aggiungiamo
##
MANPATH = / usr / local / man
[-d / usr / share / man] && MANPATH = $ MANPATH: / usr / share / man
[-d / usr / local / share / man] && MANPATH = $ MANPATH: / usr / local / share / man
[-d / usr / man] && MANPATH = $ MANPATH: / usr / man
[-d / cs / man] && MANPATH = $ MANPATH: / cs / man
[-d / usr / krb5 / man] && MANPATH = $ MANPATH: / usr / krb5 / man
[-d / usr / kerberos / man] && MANPATH = $ MANPATH: / usr / kerberos / man
[-d / usr / local / ssl / man] && MANPATH = $ MANPATH: / usr / local / ssl / man
[-d /cs/local/jdk1.5.0/man] && MANPATH = $ MANPATH: /cs/local/jdk1.5.0/man
[-d /usr/java/jre1.5.0_02/man] && MANPATH = $ MANPATH: /usr/java/jre1.5.0_02/man
[-d /usr/java1.2/man] && MANPATH = $ MANPATH: /usr/java1.2/man
[-d / usr / X11R6 / man] && MANPATH = $ MANPATH: / usr / X11R6 / man
[-d / usr / local / apache / man] && MANPATH = $ MANPATH: / usr / local / apache / man
[-d / usr / local / mysql / man] && MANPATH = $ MANPATH: / usr / local / mysql / man
[-d /cs/local/perl5.8.0/man] && MANPATH = $ MANPATH: /cs/local/perl5.8.0/man
[-d / usr / perl5 / man] && MANPATH = $ MANPATH: / usr / perl5 / man
[-d / usr / local / perl / man] && MANPATH = $ MANPATH: / usr / local / perl / man
[-d /usr/local/perl5.8.0/man] && MANPATH = $ MANPATH: /usr/local/perl5.8.0/man
[-d / usr / openwin / man] && MANPATH = $ MANPATH: / usr / openwin / man

Oltre ad avere un singolo file che posso copiare su sistemi in ambienti disparati senza timore di aggiungere directory inesistenti al PERCORSO, questo approccio ha anche il vantaggio di consentirmi di specificare l'ordine in cui le directory devono apparire nel PERCORSO. Poiché la prima riga di ogni definizione ridefinisce completamente la variabile PATH, posso aggiornare il mio .bashrc e crearlo dopo la modifica per avere la mia shell aggiornata senza aggiungere voci duplicate (che ho sperimentato molto tempo fa quando ho semplicemente iniziato con " $ PATH = $ PATH: / new / dir ". Questo mi assicura di ottenere una copia pulita nell'ordine che desidero.


1
suggerendo un'alternativa: d="/usr/share/man" ; [ -d "$d" ] && MANPATH="$MANPATH:${d}"sarà più breve e più facile aggiungere una nuova dir (basta copiare una riga e modificare la prima parte "d = ...."). Tuttavia, per quello PATH, penso che finirai con troppe dir nel tuo PATH, il che non è sempre buono (cosa succede se un comando "foo" esiste in uno dei percorsi meno conosciuti, e fai qualcosa di completamente diverso che cosa si aspetterebbe un utente normale?)
Olivier Dulac il

L'OP ha chiesto un modo più conciso per aggiungere percorsi. Questo è molto più dettagliato e più incline all'errore di quello che stavano già cercando di evitare.
underscore_d

-1

C'è un modo semplice! Leggi le funzioni della shell e le variabili di percorso sul Linux Journal , 1 marzo 2000 Di Stephen Collyer

Le funzioni mi consentono di utilizzare un nuovo tipo di dati nel mio ambiente bash: l'elenco separato da due punti. Oltre a PATH, li uso per regolare LOCATE_PATH, MANPATH e altri e come tipo di dati generale nella programmazione bash. Ecco come ho impostato il mio PERCORSO (usando le funzioni):

# Add my bin directory to $PATH at the beginning, so it overrides 
addpath -f -p PATH $HOME/bin

# For Raspberry Pi development (add at end)
addpath -b -p PATH ${HOME}/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

# remove nonexistent directories from PATH
delpath -n -p PATH

# ensure PATH contains unique entries
uniqpath -p PATH

Dato che il collegamento al Linux Journal viene definito "interrotto", ho inserito le funzioni Bash Path in un file .shar su http://pastebin.ubuntu.com/13299528/


3
Quali sono queste funzioni? Come li utilizza l'OP? Presumibilmente sono descritti nel link non funzionante nella tua risposta, motivo per cui vogliamo sempre che le risposte siano autosufficienti. Modifica e includi le funzioni effettive nella tua risposta.
terdon,

@terdon: il collegamento funziona per me, ho inserito un file .shar su pastebin, non inserirò 1K righe qui.
Waltinator,

Whoops, funziona anche per me adesso. Non è stato quando ho lasciato il commento. Comunque, l'essenza del mio commento è stata che proviamo a evitare il collegamento a risorse esterne nelle risposte. Vogliamo che le informazioni si trovino qui dove possano essere aggiornate, modificate ed è immune al marciume dei link.
terdon,
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.