Erblicken! Die industrietaugliche 12er-Linie ... technisch bash- und zsh-portable Shell - Funktion , dass Ihre hingebungsvoll liebt ~/.bashrc
oder ~/.zshrc
Startskript der Wahl:
# void +path.append(str dirname, ...)
#
# Append each passed existing directory to the current user's ${PATH} in a
# safe manner silently ignoring:
#
# * Relative directories (i.e., *NOT* prefixed by the directory separator).
# * Duplicate directories (i.e., already listed in the current ${PATH}).
# * Nonextant directories.
+path.append() {
# For each passed dirname...
local dirname
for dirname; do
# Strip the trailing directory separator if any from this dirname,
# reducing this dirname to the canonical form expected by the
# test for uniqueness performed below.
dirname="${dirname%/}"
# If this dirname is either relative, duplicate, or nonextant, then
# silently ignore this dirname and continue to the next. Note that the
# extancy test is the least performant test and hence deferred.
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname}:"* &&
-d "${dirname}" ]] || continue
# Else, this is an existing absolute unique dirname. In this case,
# append this dirname to the current ${PATH}.
PATH="${PATH}:${dirname}"
done
# Strip an erroneously leading delimiter from the current ${PATH} if any,
# a common edge case when the initial ${PATH} is the empty string.
PATH="${PATH#:}"
# Export the current ${PATH} to subprocesses. Although system-wide scripts
# already export the ${PATH} by default on most systems, "Bother free is
# the way to be."
export PATH
}
Bereite dich auf den sofortigen Ruhm vor. Dann, anstatt dies zu tun und auf das Beste zu hoffen:
export PATH=$PATH:~/opt/bin:~/the/black/goat/of/the/woods/with/a/thousand/young
Tun Sie dies stattdessen und Sie werden garantiert das Beste bekommen, egal ob Sie das wirklich wollten oder nicht:
+path.append ~/opt/bin ~/the/black/goat/of/the/woods/with/a/thousand/young
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ährend bash
und zsh
leise akzeptieren und ignoriert meist relativ dirnames in den meisten Fällen als Präfix relativ dirnames von entweder h
oder t
(und möglicherweise anderen ruchlosen Zeichen) Ursache sowohl für sich schändlich ala Masaki Kobayashi verstümmeln Samen 1962 Meisterwerk Harakiri :
# Don't try this at home. You will feel great pain.
$ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:harakiri && echo $PATH
/usr/local/bin:/usr/bin:arakiri
$ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:tanuki/yokai && echo $PATH
binanuki/yokai # Congratulations. Your system is now face-up in the gutter.
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 wie PATH=/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. (
- Versehentlich fehlende Dirnames. Auch wenn fehlende
${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 durch bash
und zsh
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:
+path.prepend() {
local dirname
for dirname in "${@}"; do
dirname="${dirname%/}"
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname}:"* &&
-d "${dirname}" ]] || continue
PATH="${dirname}:${PATH}"
done
PATH="${PATH%:}"
export PATH
}
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
und zsh
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:
+path.append() {
local dirname
for dirname in "${@}"; do
dirname="${dirname%/}"
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname:A}:"* &&
-d "${dirname}" ]] || continue
PATH="${PATH}:${dirname}"
done
PATH="${PATH#:}"
export PATH
}
Beachten Sie *":${dirname:A}:"*
eher das als *":${dirname}:"*
das Original. :A
ist ein wundersamer zsh
-ismus, der leider unter den meisten anderen muscheln fehlt - auch bash
. Um zu zitieren man zshexpn
:
A : Verwandeln Sie einen Dateinamen wie der a
Modifikator in einen absoluten Pfad und übergeben Sie das Ergebnis dann über die realpath(3)
Bibliotheksfunktion, um symbolische Verknüpfungen aufzulösen. Hinweis: Auf Systemen ohne realpath(3)
Bibliotheksfunktion werden symbolische Verknüpfungen nicht aufgelöst. Dies gilt auch für diese Systeme a
und A
ist äquivalent.
Keine weiteren Fragen.
Bitte. Viel Spaß beim sicheren Beschuss. Du hast es jetzt verdient.