Wenn Sie versuchen, eine Datei als Quelle zu verwenden, möchten Sie nicht einen Fehler erhalten, der besagt, dass die Datei nicht vorhanden ist, damit Sie wissen, was zu beheben ist?
Zum Beispiel empfiehlt nvm , dies zu Ihrem Profil / rc hinzuzufügen:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
Wenn oben nvm.sh
nicht vorhanden, wird ein "stiller Fehler" angezeigt. Aber wenn Sie es versuchen . "$NVM_DIR/nvm.sh"
, wird die Ausgabe sein FILE_PATH: No such file or directory
.
shell-script
JBallin
quelle
quelle
HOME
.Antworten:
Bei POSIX-Shells
.
handelt es sich um eine spezielle Funktion, bei deren Fehlschlagen die Shell beendet wird (bei einigen Shellsbash
wird dies nur im POSIX-Modus ausgeführt).Was als Fehler zu qualifizieren ist, hängt von der Shell ab. Nicht alle werden bei einem Syntaxfehler beim Parsen der Datei beendet, die meisten werden jedoch beendet, wenn die Quelldatei nicht gefunden oder geöffnet werden kann. Ich kenne keine, die beendet würden, wenn der letzte Befehl in der Quelldatei mit einem Beendigungsstatus ungleich Null zurückgegeben würde (es sei denn, die
errexit
Option ist natürlich aktiviert).Hier machen:
Ist ein Fall, in dem Sie die Datei als Quelle angeben möchten, wenn sie vorhanden ist, und nicht, wenn sie nicht vorhanden ist (oder hier mit leer ist
-s
).Das heißt, es sollte nicht als Fehler betrachtet werden (schwerwiegender Fehler in POSIX-Shells). Wenn die Datei nicht vorhanden ist, wird diese Datei als optionale Datei betrachtet.
Es wäre immer noch ein (schwerwiegender) Fehler, wenn die Datei nicht lesbar oder ein Verzeichnis wäre, oder (in einigen Shells), wenn beim Parsen ein Syntaxfehler aufgetreten wäre, der echte Fehlerbedingungen darstellen würde, die gemeldet werden sollten.
Einige würden argumentieren, dass es eine Rennbedingung gibt. Das einzige, was dies bedeutet, ist, dass die Shell mit einem Fehler beendet wird, wenn die Datei zwischen
[
und entfernt wird.
wird. Ich würde jedoch argumentieren, dass es sich um einen Fehler handelt, bei dem diese Datei mit festem Pfad plötzlich verschwindet, während das Skript ausgeführt wird Laufen.Auf der anderen Seite,
Wobei
command
¹ das spezielle Attribut für den.
Befehl entfernt (damit die Shell bei einem Fehler nicht beendet wird), funktioniert nicht wie folgt:.
die Fehler verbergen , aber auch die Fehler der Befehle, die in der Quelldatei ausgeführt werdenAndere gebräuchliche Syntaxen (siehe zum Beispiel
grep -r /etc/default /etc/init*
auf Debian-Systemen für die Init-Skripte, die noch nicht konvertiert wurdensystemd
(wobeiEnvironmentFile=-/etc/default/service
stattdessen eine optionale Umgebungsdatei angegeben wird)):[ -e "$file" ] && . "$file"
Überprüfen Sie die Datei, die sie enthält, und geben Sie sie weiterhin aus, wenn sie leer ist. Immer noch schwerwiegender Fehler, wenn es nicht geöffnet werden kann (obwohl es da ist oder war). Möglicherweise sehen Sie weitere Varianten wie
[ -f "$file" ]
(existiert und ist eine reguläre Datei),[ -r "$file" ]
(ist lesbar) oder Kombinationen davon.[ ! -e "$file" ] || . "$file"
Eine etwas bessere Version. Verdeutlicht, dass es sich bei der nicht vorhandenen Datei um einen OK-Fall handelt. Das bedeutet
$?
auch, dass der Exit-Status des zuletzt ausgeführten Befehls angezeigt wird$file
(im vorherigen Fall1
wissen Sie nicht, ob der$file
Befehl nicht vorhanden war oder fehlgeschlagen ist).command . "$file"
Erwarten Sie, dass die Datei dort ist, aber beenden Sie sie nicht, wenn sie nicht interpretiert werden kann.
[ ! -e "$file" ] || command . "$file"
Kombination der oben genannten Punkte: Wenn die Datei nicht vorhanden ist, ist dies in Ordnung. Bei POSIX-Shells werden Fehler beim Öffnen (oder Parsen) der Datei gemeldet, die jedoch nicht schwerwiegend sind (was für möglicherweise wünschenswerter ist
~/.profile
).¹ Hinweis: In
zsh
können Sie dies jedoch nurcommand
in dersh
Emulation verwenden. Beachten Sie, dass in der Korn-Shellsource
tatsächlich ein Alias fürcommand .
eine nicht spezielle Variante von.
quelle
.bash_profile
. Ich denke, es ist sicherer als leid, aber ist die Bash jemals im POSIX-Modus, wenn sie.bash_profile
bezogen wird?bash
wenn Sie sich nicht im POSIX-Modus befinden. Sie möchten,[ -e /file ] && . /file
dass es sich nicht um einen Fehler handelt, wenn die Datei nicht vorhanden ist. Die try-Quelle behandelt dann den Fehler, falls dies hier nicht möglich ist..
meldet bereits einen Fehler (auf stderr). Und wenn die Absicht besteht, es nicht als Fehler zu betrachten, wenn die Datei nicht vorhanden ist, ist dies nicht korrekt (und es ist nicht möglich, anhand des Beendigungsstatus zu erkennen, ob ein Fehler aufgetreten ist,.
weil die Datei nicht vorhanden oder nicht lesbar war oder war nicht analysierbar, oder der letzte Befehl ist fehlgeschlagen), das sind die Punkte, die ich hier in dieser Antwort mache.Betreuer der
nvm
Antwort:Meine Interpretation (kombiniert mit Stéphanes hervorragender Erklärung und Kusalanandas Kommentar):
Es ist einfacher und sicherer.
Es schützt vor POSIX-Shells, die beim Start aufgrund einer fehlenden Datei (aus verschiedenen Gründen) beendet werden. Benutzer von Nicht-POSIX-Shells (z. B. Bash-Shells) können die Bedingung gegebenenfalls entfernen.
quelle
/etc
, können einige Benutzer die Datei haben und andere nicht. Meiner Meinung nachnvm
berührt die Antwort des Betreuers nur einen Aspekt.Wie JBallin und Stéphane Chazelas in POSIX-Shells ausgeführt haben, würde die Suche nach einer Datei, die nicht vorhanden ist, zum Fehlschlagen der Anmeldung führen.
Wenn Sie jedoch einen Test hinzufügen, um festzustellen, ob die Datei vorhanden ist, und dann versuchen, sie als Quelle zu verwenden, kann dies zu einer so genannten Race Condition führen. Wenn sich etwas
nvm.sh
zwischen dem[ -s nvm.sh ]
und dem ändert. nvm.sh
, verursacht dies genau den Fehler, den sie zu verhindern versuchen, wenn auch viel seltener.Im Allgemeinen können Sie Wettkampfbedingungen verhindern, indem Sie einfach das versuchen, was Sie tun möchten, und den Fehler dann behandeln, wenn er fehlschlägt, z
Es stellt sich heraus, dass dies in POSIX-Shells nicht funktioniert, da
.
die Shell , wie oben beschrieben, beim Fehlschlagen sofort beendet wird, bevor eine Fehlerbehandlung ausgeführt werden kann.Meine Antwort lautet, dass POSIX-Shells für diese Frage nicht relevant sind, da
.bash_profile
sie niemals im POSIX-Modus ausgeführt werden sollten. Also können wir den obigen Code trotzdem machen.Um die Sicherheit zu gewährleisten, können wir mithilfe der unter /unix//a/383581/3169 beschriebenen Technik sicherstellen, dass der POSIX-Modus nicht aktiviert ist oder dass der POSIX-Modus deaktiviert ist .
Die Antwort von Stéphane enthält einige nützliche Vorschläge für den Umgang mit allen POSIX-Shells. Ich denke, das war die Absicht des Autors von nvm, aber sie unterschied sich geringfügig von der Frage, die hier gestellt wurde. Aus diesem Grund haben wir mehrere mögliche Ansätze, je nachdem, welches Ziel Sie verfolgen .
quelle