Ich möchte eine Möglichkeit haben, Dinge systemweit oder für einen einzelnen Benutzer zu $ PATH hinzuzufügen, ohne möglicherweise den gleichen Pfad mehrmals hinzuzufügen.
Ein Grund, dies zu tun, besteht darin, dass Ergänzungen vorgenommen werden können, für .bashrc
die keine Anmeldung erforderlich ist, und dies ist auch auf Systemen, die (z. B.) verwenden lightdm
und die niemals anrufen, nützlicher .profile
.
Ich kenne Fragen zum Entfernen von Duplikaten aus $ PATH, möchte jedoch keine Duplikate entfernen . Ich möchte eine Möglichkeit, Pfade nur hinzuzufügen, wenn sie nicht bereits vorhanden sind.
Antworten:
Angenommen, der neue Pfad, den wir hinzufügen möchten, lautet:
Dann können wir mit einer beliebigen POSIX-Shell testen, ob
new
sich bereits ein Pfad befindet, und ihn hinzufügen, wenn dies nicht der Fall ist:Beachten Sie die Verwendung von Doppelpunkten. Ohne die Doppelpunkte könnten wir denken, dass sie
new=/bin
sich beispielsweise bereits auf dem Weg befanden, weil sie mit dem Muster übereinstimmten/usr/bin
. Während PATHs normalerweise viele Elemente enthalten, werden auch die Sonderfälle von Null- und Eins-Elementen im PATH behandelt. Der Fall, dass der PATH anfänglich keine Elemente enthält (leer ist), wird durch die Verwendung behandelt,${PATH:=$new}
die zuweistPATH
,$new
wenn er leer ist. Das Festlegen von Standardwerten für Parameter auf diese Weise ist eine Funktion aller POSIX-Shells: siehe Abschnitt 2.6.2 der POSIX-Dokumente .)Eine aufrufbare Funktion
Der Einfachheit halber kann der obige Code in eine Funktion eingefügt werden. Diese Funktion kann in der Befehlszeile definiert oder dauerhaft im Initialisierungsskript Ihrer Shell abgelegt werden (für Bash-Benutzer wäre dies
~/.bashrc
):So verwenden Sie diese Pfadaktualisierungsfunktion, um dem aktuellen PFAD ein Verzeichnis hinzuzufügen:
quelle
PATH
leer, wird ein leerer Eintrag (dh das aktuelle Verzeichnis) zum. HinzugefügtPATH
. Ich denke, Sie brauchen einen anderen Fall.case
. Tu es einfachcase "${PATH:=$new}"
. Siehe meine eigene Antwort für ähnliche Fallbacks.Erstellen Sie eine Datei in
/etc/profile.d
aufgerufen, zBmypath.sh
(oder was auch immer Sie wollen). Wenn Sie Lightdm verwenden, stellen Sie sicher, dass es funktionsfähig ist, oder verwenden Sie/etc/bashrc
eine Datei, die von derselben stammt. Dazu kommen folgende Funktionen:Dinge am Anfang von (vor) $ PATH haben Vorrang vor dem, was folgt, und umgekehrt werden Dinge am Ende (angefügt) durch das, was vorher kommt, abgelöst. Dies bedeutet, wenn Ihr $ PATH ist
/usr/local/bin:/usr/bin
undgotcha
in beiden Verzeichnissen eine ausführbare Datei vorhanden ist/usr/local/bin
, wird standardmäßig diejenige in verwendet.Sie können jetzt - in derselben Datei, in einer anderen Shell-Konfigurationsdatei oder über die Befehlszeile - Folgendes verwenden:
Wenn dies in a steht
.bashrc
, wird verhindert, dass der Wert mehrmals angezeigt wird, wenn Sie eine neue Shell starten. Es gibt eine Einschränkung: Wenn Sie etwas anhängen möchten, das vorangestellt wurde (dh einen Pfad innerhalb von $ PATH verschieben) oder umgekehrt, müssen Sie dies selbst tun.quelle
$PATH
mitIFS=:
ist letztendlich flexibler alscase
.case
IMO. Ich kann mir vorstellen, dassawk
auch hier eine gute Verwendung gefunden werden könnte.gawk
direkt zuordnen können$PATH
.Du kannst es so machen:
Hinweis: Wenn Sie PATH aus anderen Variablen erstellen, stellen Sie sicher, dass diese nicht leer sind. Viele Shells interpretieren "" wie ". .
quelle
-q
ist POSIX für grep erforderlich, aber ich weiß nicht, ob das bedeutet, dass es noch einige (nicht POSIX) greps gibt, die es nicht haben./my/bin
Der wichtige Teil des Codes besteht darin, zu überprüfen, ob
PATH
ein bestimmter Pfad enthalten ist:Stellen Sie also sicher, dass jeder Pfad
PATH
auf beiden Seiten durch dasPATH
Trennzeichen (:
) begrenzt ist, und überprüfen Sie (-q
), ob die Literalzeichenfolge (-F
) aus einemPATH
Trennzeichen, Ihrem Pfad und einem anderen bestehtPATH
Trennzeichen besteht, dort vorhanden ist. Wenn dies nicht der Fall ist, können Sie den Pfad problemlos hinzufügen:Dies sollte POSIX-kompatibel sein und mit jedem Pfad funktionieren, der kein Zeilenumbruchzeichen enthält. Es ist komplexer, wenn Sie möchten, dass es mit Pfaden funktioniert, die Newline enthalten, während es POSIX-kompatibel ist. Wenn Sie jedoch einen haben,
grep
der dies unterstützt-z
, können Sie diesen verwenden.quelle
Ich habe diese kleine Funktion
~/.profile
seit Jahren in verschiedenen Akten mit mir herumgetragen. Ich glaube, es wurde vom Sysadmin in einem Labor geschrieben, in dem ich gearbeitet habe, aber ich bin mir nicht sicher. Wie auch immer, es ist Goldilocks Ansatz ähnlich, aber ein wenig anders:So fügen Sie ein neues Verzeichnis am Anfang des folgenden Befehls hinzu
PATH
:und bis zum ende:
quelle
/bin/grep
->grep
AKTUALISIEREN:
Mir ist aufgefallen, dass Ihre eigene Antwort eine separate Funktion zum Anhängen oder Voranstellen an die hat
$PATH
. Mir hat die Idee gefallen. Also habe ich ein kleines Argument hinzugefügt. Ich habe es auch richtig mit einem_
Namensraum versehen:AUSGABE:
Standardmäßig wird es
-A
angehalten$PATH
, aber Sie können dieses Verhalten-P
ändern, indem Sie an einer-P
beliebigen Stelle in Ihrer Argumentliste ein neues Argument hinzufügen . Sie können es wieder in den-A
Standby-Modus versetzen, indem Sie es-A
erneut geben.SICHERES EVAL
In den meisten Fällen empfehle ich, dass Menschen jede Verwendung von vermeiden
eval
. Aber ich denke, dies ist ein gutes Beispiel für seine Verwendung . In diesem Fall ist oder die einzige Anweisung,eval
die jemals angezeigt werden kann . Die Werte seiner Argumente werden streng geprüft, bevor sie aufgerufen werden. Dafür ist .P=
A=
eval
Dies akzeptiert so viele Argumente, wie Sie angeben, und fügt sie jeweils
$PATH
nur einmal und nur dann hinzu, wenn sie nicht bereits vorhanden sind$PATH
. Es wird nur ein vollständig portierbares POSIX-Shell-Skript verwendet, es basiert nur auf integrierten Shell-Funktionen und ist sehr schnell.quelle
_
vorangestellten Shell-Funktionen dafür sorgen, dass sie einen "richtigen Namensraum" haben? In anderen Sprachen gibt es normalerweise eine interne globale Funktion an (dh eine, die global sein muss, aber nicht für die externe Verwendung als Teil einer API vorgesehen ist). Meine Namen sind mit Sicherheit keine gute Wahl, aber es scheint mir_
, dass Kollisionsprobleme durch die Verwendung von überhaupt nicht gelöst werden - es wäre besser, einen tatsächlichen Namespace zu verwenden, z.mikeserv_path_assign()
._
, müssen Sie die Paketmanager wechseln. In jedem Fall handelt es sich im Wesentlichen nur um eine "globale, interne Funktion" - sie ist global für jede Shell, die von der Shell aufgerufen wird, in der sie deklariert wurde, und es handelt sich nur um ein interpretiertes Sprachskript, das im Speicher des Interpreters hängt . unix.stackexchange.com/questions/120528/…unset a
(oder gleichwertig) am Ende des Profils?Erblicken! Die industrietaugliche 12er-Linie ... technisch bash- und zsh-portable Shell - Funktion , dass Ihre hingebungsvoll liebt
~/.bashrc
oder~/.zshrc
Startskript der Wahl:Bereite dich auf den sofortigen Ruhm vor. Dann, anstatt dies zu tun und auf das Beste zu hoffen:
Tun Sie dies stattdessen und Sie werden garantiert das Beste bekommen, egal ob Sie das wirklich wollten oder nicht:
Sehr gut, definieren Sie "am besten".
Das sichere Anhängen und Voranstellen an die aktuelle Situation
${PATH}
ist keine alltägliche Angelegenheit. Obwohl es praktisch und vernünftig erscheint,export PATH=$PATH:~/opt/bin
laden Einzeiler der Form teuflische Komplikationen ein mit:Versehentlich relative Dirnames (zB
export PATH=$PATH:opt/bin
). Währendbash
undzsh
leise akzeptieren und ignoriert meist relativ dirnames in den meisten Fällen als Präfix relativ dirnames von entwederh
odert
(und möglicherweise anderen ruchlosen Zeichen) Ursache sowohl für sich schändlich ala Masaki Kobayashi verstümmeln Samen 1962 Meisterwerk Harakiri :Versehentlich doppelte Dirnames. Während doppelte
${PATH}
Dirnames weitgehend harmlos sind, sind sie auch unerwünscht, umständlich, leicht ineffizient, beeinträchtigen die Debug-Fähigkeit und fördern den Verschleiß des Laufwerks - wie diese Antwort. Während SSDs im NAND-Stil ( natürlich ) unempfindlich gegen Leseverschleiß sind, sind dies HDDs nicht. Unnötiger Zugriff auf das Dateisystem bei jedem versuchten Befehl führt zu unnötigem Verschleiß des Lesekopfs im selben Tempo. Duplikate sind besonders unsauber, wenn Sie verschachtelte Shells in verschachtelten Unterprozessen aufrufen. An diesem Punkt sollten Sie scheinbar harmlose Einzeiler wie " Lassen Sie dies nicht zu, dass Ihre kostbaren Kinder dies tun". )export PATH=$PATH:~/wat
explodieren schnell in den siebten Kreis von${PATH}
der Hölle wiePATH=/usr/local/bin:/usr/bin:/bin:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat
. Nur Beelzebubba kann Ihnen helfen, wenn Sie zusätzliche Verzeichnisnamen anhängen. (${PATH}
Dirnames weitgehend harmlos sind, sind sie in der Regel unerwünscht, umständlich, wenig effizient, beeinträchtigen die Debug-Fähigkeit und fördern den Verschleiß des Laufwerks.Ergo, freundliche Automatisierung wie die oben definierte Shell-Funktion. Wir müssen uns vor uns selbst retten.
Aber ... Warum "+ path.append ()"? Warum nicht einfach append_path ()?
Für Disambiguierung (zB mit externen Kommandos in den aktuellen
${PATH}
oder systemweite Shell - Funktionen definierten an anderer Stelle), benutzerdefinierte Shell - Funktionen sind ideal als Präfix oder Suffix mit einzigartigem Teil unterstützt durchbash
undzsh
ansonsten aber für Standardbefehl Basisnamen verboten - wie, sagen sie,+
.Hallo. Es klappt. Verurteile mich nicht.
Aber ... Warum "+ path.append ()"? Warum nicht "+ path.prepend ()"?
Weil das Anhängen an den Strom
${PATH}
sicherer ist als das Voranhängen an den Strom${PATH}
, wenn alle Dinge gleich sind, was sie niemals sind. Das Überschreiben systemweiter Befehle mit benutzerspezifischen Befehlen kann bestenfalls unhygienisch sein und schlimmstenfalls verrückt machen. Unter Linux beispielsweise erwarten nachgelagerte Anwendungen üblicherweise die Befehlsvarianten GNU coreutils und nicht benutzerdefinierte, nicht standardmäßige Derivate oder Alternativen.Allerdings gibt es dafür durchaus gültige Use Cases. Das Definieren der äquivalenten
+path.prepend()
Funktion ist trivial. Sans Prolix-Nebel, für seine und ihre gemeinsame Vernunft:Aber ... warum nicht Gilles?
Gilles ' akzeptierte Antwort an anderer Stelle ist im allgemeinen Fall als "Shell Agnostic Idempotent Append" eindrucksvoll optimal . Im gemeinsamen Fall
bash
undzsh
mit keiner unerwünschten Symlinks jedoch erforderlich , die Leistungseinbuße so betrübt das zu tun Gentoo ricer in mir. Selbst bei unerwünschten Symlinks ist es fraglich, ob pro Subshell eine gegabelt wirdadd_to_PATH()
Argument die mögliche Einfügung von Symlink-Duplikaten wert ist.Für strenge Anwendungsfälle, bei denen sogar die Beseitigung von Symlink-Duplikaten gefordert ist, erfolgt dies in dieser
zsh
spezifischen Variante über effiziente eingebaute und nicht über ineffiziente Gabeln:Beachten Sie
*":${dirname:A}:"*
eher das als*":${dirname}:"*
das Original.:A
ist ein wundersamerzsh
-ismus, der leider unter den meisten anderen muscheln fehlt - auchbash
. Um zu zitierenman zshexpn
:Keine weiteren Fragen.
Bitte. Viel Spaß beim sicheren Beschuss. Du hast es jetzt verdient.
quelle
Hier ist meine Version im funktionalen Programmierstil.
*PATH
nicht nur für alle durch Doppelpunkte getrennten VariablenPATH
.Bemerkenswert auch:
export
ing; das bleibt dem Anrufer überlassen (siehe Beispiele)bash
; kein gabelnquelle
Mit diesem Skript können Sie am Ende hinzufügen
$PATH
:Oder am Anfang hinzufügen
$PATH
:quelle