Wie füge ich einen Pfad korrekt zu PATH hinzu?

923

Ich frage mich, wo ein neuer Pfad zur PATHUmgebungsvariablen hinzugefügt werden muss. Ich weiß, dass dies durch Bearbeiten .bashrc(zum Beispiel) erreicht werden kann, aber es ist nicht klar, wie dies getan werden soll.

Diesen Weg:

export PATH=~/opt/bin:$PATH

oder dieses?

export PATH=$PATH:~/opt/bin
Paolo
quelle
printf '\ nPATH = $ PATH: "Pfad zum Hinzufügen" \ nexport PATH \ n' >> ~ / .bashrc
Sudoer
Wenn bereits einige Pfade hinzugefügt wurden PATH=$PATH:$HOME/.local/bin:$HOME/bin, kann ein anderer hinzugefügt werden, indem mit einem: z PATH=$PATH:$HOME/.local/bin:$HOME/bin:/home/ec2-user/pear/bin.
Sandeepan Nath
2
Funktionieren diese Antworten für alle Linux-Varianten?
Ungeheuer

Antworten:

1033

Das einfache Zeug

PATH=$PATH:~/opt/bin

oder

PATH=~/opt/bin:$PATH

Je nachdem, ob Sie ~/opt/binam Ende hinzufügen möchten (um nach allen anderen Verzeichnissen gesucht zu werden, falls es in mehreren Verzeichnissen ein gleichnamiges Programm gibt) oder am Anfang (um vor allen anderen Verzeichnissen gesucht zu werden).

Sie können mehrere Einträge gleichzeitig hinzufügen. PATH=$PATH:~/opt/bin:~/opt/node/binoder abweichungen von der bestellung funktionieren einwandfrei. Nicht exportam Anfang der Zeile einfügen, da dies zusätzliche Komplikationen mit sich bringt (siehe unten unter „Hinweise zu anderen Muscheln als Bash“).

Wenn Ihr PATHSystem aus vielen verschiedenen Komponenten besteht, werden möglicherweise doppelte Einträge angezeigt. Weitere Informationen finden Sie unter So fügen Sie den Pfad des Basisverzeichnisses hinzu, der von Unix ermittelt werden soll. und Entfernen Sie doppelte $ PATH-Einträge mit dem Befehl awk , um zu vermeiden, dass Duplikate hinzugefügt oder entfernt werden.

Einige Distributionen fügen ~/binIhren PATH übrigens automatisch hinzu, falls vorhanden.

Wo soll ich es hinstellen?

Setzen Sie die zu ändernde Zeile PATHein ~/.profile, oder setzen Sie sie ein, ~/.bash_profilewenn Sie dies möchten.

Beachten Sie, dass ~/.bash_rcdies von keinem Programm gelesen wird und dass ~/.bashrces sich um die Konfigurationsdatei interaktiver Instanzen von bash handelt. Sie sollten keine Umgebungsvariablen in definieren ~/.bashrc. Der richtige Ort zum Definieren von Umgebungsvariablen wie PATHist ~/.profile(oder ~/.bash_profilewenn Sie sich nicht für andere Shells als bash interessieren). Siehe Was ist der Unterschied zwischen ihnen und was soll ich verwenden?

Setzen Sie es nicht in /etc/environmentoder ~/.pam_environment: Dies sind keine Shell-Dateien, Sie können keine Ersetzungen wie $PATHdort verwenden. In diesen Dateien können Sie eine Variable nur überschreiben, nicht jedoch hinzufügen.

Mögliche Komplikationen bei einigen Systemskripten

Dies ist nicht erforderlich, exportwenn sich die Variable bereits in der Umgebung befindet. Jede Änderung des Werts der Variablen PATHwirkt sich auf die Umgebung aus. Alle Unix-Systeme haben es sehr früh eingestellt (normalerweise sogar im ersten Prozess).

Bei der Anmeldung können Sie sich darauf verlassen, dass Sie sich PATHbereits in der Umgebung befinden und einige Systemverzeichnisse enthalten. Wenn Sie ein Skript schreiben, das möglicherweise vorzeitig ausgeführt wird, während Sie eine virtuelle Umgebung einrichten , müssen Sie möglicherweise sicherstellen, dass PATHes nicht leer und exportiert ist: Wenn PATHes immer noch nicht gesetzt ist, wird etwas wie auf und die leere Komponente gesetzt am anfang steht das aktuelle verzeichnis (like ).PATH=$PATH:/some/directoryPATH:/some/directory.:/some/directory

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

Anmerkungen zu anderen Muscheln als Bash

In bash, ksh und zsh, exportist eine spezielle Syntax, und beide PATH=~/opt/bin:$PATHund export PATH=~/opt/bin:$PATHdas Richtige zu tun , auch. In anderen Bourne / POSIX-Shells wie dash ( /bin/shauf vielen Systemen) wird exportes als gewöhnlicher Befehl analysiert, der zwei Unterschiede impliziert:

So in Shells wie Bindestrich, export PATH=~/opt/bin:$PATHsetzt PATHauf die Zeichenkette ~/opt/bin/:mit dem Wert , gefolgt von PATHauf den ersten Platz. PATH=~/opt/bin:$PATH(eine bloße Aufgabe) erfordert keine Anführungszeichen und tut das Richtige. Wenn Sie exportin einem portablen Skript verwenden möchten , müssen Sie schreiben export PATH="$HOME/opt/bin:$PATH"oder PATH=~/opt/bin:$PATH; export PATH(oder PATH=$HOME/opt/bin:$PATH; export PATHaus Gründen der Portabilität auch auf die Bourne-Shell, die keine export var=valueTilde-Erweiterung akzeptiert hat).

¹ Bei Bourne-Shells stimmte dies nicht (wie bei der eigentlichen Bourne-Shell, nicht bei modernen POSIX-Shells), aber es ist sehr unwahrscheinlich, dass Sie heutzutage auf solche alten Shells stoßen.

Gilles
quelle
Immer noch nicht in der Lage, die Komplikation mit dem Export zu verstehen. kannst du es bitte vereinfachen
Priojeet Priyom
@priojeetpriyom Einfache Erklärung: Sie brauchen nicht export.
Gilles,
Vielen Dank für diese Antwort, perfekt detailliert. Sie sagen " Sie sollten keine Umgebungsvariablen in ~ / .bashrc definieren ", aber leider ändern 100% der Programme, die ich auf meinem System installiert habe, die den Pfad ändern (FZF und Rusts Cargo), den Pfad in .bashrc. Ich gehe davon aus, dass FZF auch in Rust geschrieben ist und dem Muster von Rust folgt.
ICC97
83

So oder so funktioniert es, aber sie tun nicht dasselbe: Die Elemente von PATHwerden von links nach rechts überprüft. In Ihrem ersten Beispiel haben ausführbare Dateien in ~/opt/binVorrang vor den installierten Dateien , z. B. in /usr/bin, die Ihren Wünschen entsprechen oder nicht.

Insbesondere unter Sicherheitsaspekten ist es gefährlich, Pfade nach vorne hinzuzufügen, da jemand, der Schreibzugriff auf Ihr ~/opt/binKonto erhalten kann, beispielsweise ein anderes lsdarin ablegen kann, das Sie dann wahrscheinlich stattdessen verwenden würden von /bin/lsohne es zu merken. Stellen Sie sich nun das Gleiche für sshoder Ihren Browser oder Ihre Wahl vor ...

Ulrich Schwarz
quelle
6
Wenn Sie jedoch eine eigene, angepasste Version von haben möchten, müssen Sie lssie in ein Verzeichnis vorlegen /bin.
Barmar,
16
oder alias ls = myls
waltinator
36

Ich bin durch Frage 2 verwirrt (da aus der Frage entfernt, da dies auf ein nicht damit zusammenhängendes Problem zurückzuführen ist):

Was ist eine praktikable Methode, um mehr Pfade in verschiedenen Zeilen anzufügen? Anfangs dachte ich, das könnte den Trick machen:

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

Dies ist jedoch nicht der Fall, da die zweite Zuweisung nicht nur angehängt wird ~/opt/node/bin, sondern auch die gesamte PATHzuvor zugewiesene Zuweisung.

Dies ist eine mögliche Problemumgehung:

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

Aus Gründen der Lesbarkeit würde ich es vorziehen, eine Zuordnung für einen Pfad zu haben.

Wenn du sagst

PATH=~/opt/bin

Das ist alles , was in deinem WEG sein wird. PATH ist nur eine Umgebungsvariable. Wenn Sie dem PATH etwas hinzufügen möchten, müssen Sie die Variable mit genau dem gewünschten Inhalt neu erstellen. Das heißt, was Sie als Beispiel für Frage 2 geben, ist genau das, was Sie tun möchten, es sei denn, ich verpasse den Punkt der Frage völlig.

Ich benutze beide Formulare in meinem Code. Ich habe ein generisches Profil, das ich auf jedem Computer installiere, auf dem ich arbeite. Es sieht folgendermaßen aus, um potenziell fehlende Verzeichnisse zu berücksichtigen:

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
Carl Cravens
quelle
2
Sie haben recht mit dem Beispiel von Frage 2, es funktioniert. Ein anderes PATH-Problem auf meinem System hat mich verwirrt. Das tut mir leid.
Paolo
26

Die kugelsichere Art des Anhängens / Vorbereitens

Bei der Wahl zwischen Anhängen und Voranstellen sind viele Überlegungen zu berücksichtigen. Viele von ihnen werden in anderen Antworten behandelt, deshalb werde ich sie hier nicht wiederholen.

Ein wichtiger Punkt ist, dass, selbst wenn Systemskripte dies nicht verwenden (ich frage mich, warum) * 1 , die kugelsichere Methode zum Hinzufügen eines Pfads (z. B. $HOME/bin) zur Umgebungsvariablen PATH lautet

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

zum Anhängen (anstelle von PATH="$PATH:$HOME/bin") und

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

zum Voranstellen (statt PATH="$HOME/bin:$PATH")

Dies vermeidet den falschen vorderen / hinteren Doppelpunkt, wenn er $PATHanfangs leer ist, was unerwünschte Nebenwirkungen haben und zu einem schwer zu findenden Albtraum werden kann ( diese Antwort behandelt kurz den Fall des awkWeges).

Erklärung (aus Shell Parameter Expansion ):

${parameter:+word}

Wenn parameternull oder nicht gesetzt ist, wird nichts ersetzt, andernfalls wird die Erweiterung von wordersetzt.

Somit ${PATH:+${PATH}:}wird erweitert zu: 1) nichts, wenn PATHnull oder nicht gesetzt ist, 2) ${PATH}:wenn PATHgesetzt ist.

Hinweis : Dies ist für die Bash.


* 1 Ich habe gerade festgestellt, dass Skripte wie diese devtoolset-6/enabletatsächlich verwenden,

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

Linux bestimmt den ausführbaren Suchpfad mit der $PATHUmgebungsvariablen. $PATHVerwenden Sie Folgendes, um das Verzeichnis / data / myscripts am Anfang der Umgebungsvariablen hinzuzufügen :

PATH=/data/myscripts:$PATH

Verwenden Sie den folgenden Befehl, um dieses Verzeichnis am Ende des Pfads hinzuzufügen:

PATH=$PATH:/data/myscripts

Die vorhergehenden sind jedoch nicht ausreichend, da diese Änderung nur innerhalb des Skripts wirksam wird, wenn Sie eine Umgebungsvariable innerhalb eines Skripts festlegen. Es gibt nur zwei Möglichkeiten, um diese Einschränkung zu umgehen:

  • Wenn Sie die Umgebungsvariable innerhalb des Skripts exportieren, ist sie in allen vom Skript aufgerufenen Programmen wirksam. Beachten Sie, dass es in dem Programm, das das Skript aufgerufen hat, nicht wirksam ist.
  • Wenn das Programm, das das Skript aufruft, dies durch Einbeziehung statt durch Aufrufen tut, werden alle Umgebungsänderungen im Skript im aufrufenden Programm wirksam. Eine solche Einbeziehung kann mit dem Punktbefehl oder dem Quellbefehl erfolgen.

Beispiele:

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

Inklusion bezieht grundsätzlich das "aufgerufene" Skript in das "aufrufende" Skript ein. Es ist wie ein #include in C. Also ist es innerhalb des "aufrufenden" Skripts oder Programms wirksam. Aber natürlich ist es in Programmen oder Skripten, die vom aufrufenden Programm aufgerufen werden, nicht wirksam. Damit es in der gesamten Aufrufkette wirksam wird, müssen Sie die Einstellung der Umgebungsvariablen mit einem Exportbefehl verfolgen.

Als Beispiel bezieht das Bash-Shell-Programm den Inhalt der Datei .bash_profile durch Einbeziehung mit ein. Fügen Sie die folgenden 2 Zeilen in .bash_profile ein:

PATH=$PATH:/data/myscripts
export PATH

Fügt diese beiden Codezeilen effektiv in das Bash-Programm ein. Daher enthält die Variable $ PATH in bash $HOME/myscript.shund aufgrund der export-Anweisung alle von bash aufgerufenen Programme die geänderte $PATHVariable. Und da alle Programme, die Sie an einer Bash-Eingabeaufforderung ausführen, von der Bash aufgerufen werden, ist der neue Pfad für alle von der Bash-Eingabeaufforderung aus ausgeführten Aktionen gültig.

Um dem Pfad ein neues Verzeichnis hinzuzufügen, müssen Sie das Verzeichnis an die Umgebungsvariable $ PATH in einem in der Shell enthaltenen Skript anhängen oder voranstellen und die $PATHUmgebungsvariable exportieren .

Mehr Infos hier

Steve Brown
quelle
19

Seit einiger Zeit habe ich mir zwei Funktionen gehalten pathaddund pathrmdie Unterstützung bei Hinzufügen von Elementen zu dem Weg , ohne die Notwendigkeit , sich um Doppelungen zu kümmern.

pathaddEs wird ein einzelnes Pfadargument und ein optionales afterArgument verwendet, das, falls angegeben, an das Argument PATHangehängt wird, dem es sonst vorangeht.

In fast jeder Situation, in der Sie dem Pfad etwas hinzufügen, möchten Sie wahrscheinlich alles, was sich bereits im Pfad befindet, überschreiben. Aus diesem Grund bevorzuge ich standardmäßig.

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')"
}

Fügen Sie diese in ein beliebiges Skript ein, das Sie zum Ändern der PATH-Umgebung verwenden möchten. Dies ist jetzt möglich.

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

Sie werden garantiert nicht zum Pfad hinzugefügt, wenn er bereits vorhanden ist. Wenn Sie jetzt sicherstellen möchten, /baz/batist am Start.

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

Jetzt kann jeder Pfad nach vorne verschoben werden, wenn er sich bereits im Pfad befindet, ohne sich zu verdoppeln.

Brett Ryan
quelle
Verwandte und übersichtlichere Methode
Wildcard
9

Ich kann nicht für andere Distributionen sprechen, aber Ubuntu hat eine Datei, / etc / environment, das ist der Standard-Suchpfad für alle Benutzer. Da mein Computer nur von mir verwendet wird, füge ich alle gewünschten Verzeichnisse in meinen Pfad ein, es sei denn, es handelt sich um eine temporäre Ergänzung, die ich in ein Skript eingefügt habe.

Jim Bradley
quelle
6

Es gibt einige Situationen, in denen die Verwendung PATH=/a/b:$PATHals "falsche" Methode zum Hinzufügen eines Pfads zu PATHfolgenden Elementen angesehen werden kann :

  1. Hinzufügen eines Pfads, der eigentlich kein Verzeichnis ist.
  2. Hinzufügen eines Pfads, der sich bereits in PATHderselben Form befindet.
  3. Hinzufügen eines relativen Pfads (da sich das tatsächlich gesuchte Verzeichnis ändern würde, wenn Sie das aktuelle Arbeitsverzeichnis ändern).
  4. Hinzufügen eines Pfads, der sich bereits in PATHeiner anderen Form befindet (z. B. ein Alias ​​aufgrund der Verwendung von Symlinks oder ..).
  5. Wenn Sie 4 vermeiden, verschieben Sie den Pfad nicht nach vorne, PATHwenn andere Einträge in überschrieben werden sollen PATH.

Diese (Nur-Bash) -Funktion erledigt in den oben genannten Situationen das "Richtige" (mit einer Ausnahme, siehe unten), gibt Fehlercodes zurück und druckt nette Nachrichten für Menschen. Die Fehlercodes und Meldungen können deaktiviert werden, wenn sie nicht gewünscht werden.

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"
}

Die Ausnahme besteht darin, dass diese Funktion keine Pfade kanonisiert, die auf PATHandere Weise hinzugefügt wurden. Wenn sich also ein nicht-kanonischer Alias ​​für einen Pfad in befindet PATH, wird ein Duplikat hinzugefügt. Der Versuch, bereits vorhandene Pfade zu PATHkanonisieren, ist eine heikle Angelegenheit, da ein relativer Pfad eine offensichtliche Bedeutung hat, wenn er an übergeben wird. Wenn er sich prepathjedoch bereits im Pfad befindet, wissen Sie nicht, wie das aktuelle Arbeitsverzeichnis lautete, als er hinzugefügt wurde.

Curt J. Sampson
quelle
in Bezug auf relative Pfade: Wie wäre es mit einem '-r'-Schalter, der den Pfad hinzufügt, ohne ihn zuerst absolut zu machen, und der ihn auch als absolut ansieht, bevor er hinzugefügt wird? Wenn dies ein Skript wäre, könnte man es in anderen Shells verwenden. Gibt es einen Vorteil, wenn man es als Funktion hat? netter Code!
Hoijui
1
@hoijui Es muss eine Funktion sein, da sie die aktuelle Umgebung verändert. Wenn es ein Skript wäre, würde es die Umgebung des Unterprozesses ändern, in dem das Skript ausgeführt wird, und wenn das Skript beendet wird, würden Sie dasselbe $PATHwie zuvor haben. Was -r, nein, ich denke , dass relative Pfade in $PATHsind einfach zu unzuverlässig und seltsam (Ihr Weg jedes Mal ändert Sie cd!) So etwas wie das in einem allgemeinen Werkzeug zur Unterstützung wollen.
Curt J. Sampson
5

Für mich (unter Mac OS X 10.9.5) hat das Hinzufügen des Pfadnamens (z. B. /mypathname) zur Datei /etc/pathssehr gut funktioniert.

Vor dem Bearbeiten wird echo $PATHFolgendes zurückgegeben:

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

Nach dem Bearbeiten /etc/pathsund Neustarten der Shell wird die Variable $ PATH angehängt /pathname. Gibt in der Tat Folgendes echo $PATHzurück:

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

Was passiert ist, ist, dass /mypathnamean die $PATHVariable angehängt wurde .

faelx
quelle
3
Es ist besser, eine Datei zum Verzeichnis /etc/paths.d hinzuzufügen, als die Datei /etc/paths selbst zu bearbeiten.
Rbrewer
4

So fügen Sie der PATHUmgebungsvariablen einen neuen Pfad hinzu :

export PATH=$PATH:/new-path/

Für diese Änderung zu jeder Schale aufgebracht werden Sie öffnen, fügen Sie ihn in die Datei , die die Shell beziehen , wenn es aufgerufen wird. In verschiedenen Schalen kann dies sein:

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

z.B

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

Sie können den angegebenen Pfad in der obigen Ausgabe sehen.

Amit24x7
quelle
4

Hier ist meine Lösung:

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

Ein schöner, leichter Einzeiler, der kein Nachlaufen hinterlässt :

AJ.
quelle
1
-bash: awk: Keine solche Datei oder Verzeichnis -bash: sed: Keine solche Datei oder Verzeichnis
Davidcondrey
1
@davidcondrey - awk und sed sind sehr häufige externe Befehle. Diese Antwort bietet eine reine bash-Methode, um dasselbe zu erreichen. Sie funktioniert also auch in Fällen, in denen awk und / oder sed nicht vorhanden sind (oder die entsprechenden Verzeichnisse nicht im Pfad enthalten sind!)
sancho.s