Hier ist ein Befehl, der sowohl unter Bash als auch unter zsh funktioniert, und zwar unabhängig davon, ob er eigenständig oder als Quellcode ausgeführt wird:
[ -n "$ZSH_VERSION" ] && this_dir=$(dirname "${(%):-%x}") \
|| this_dir=$(dirname "${BASH_SOURCE[0]:-$0}")
Wie es funktioniert
Die aktuelle Dateierweiterung von zsh: ${(%):-%x}
${(%):-%x}
in zsh expandiert zum Pfad der gerade ausgeführten Datei.
Der Fallback-Substitutionsoperator :-
Sie wissen bereits, dass ${...}
ersetzt Variablen innerhalb von Zeichenketten. Sie wissen vielleicht nicht, dass bestimmte Operationen möglich sind (sowohl in Bash y zsh ) auf die Variablen während der Substitution, wie der Fallback-Expansionsoperator :-
:
% x=ok
% echo "${x}"
ok
% echo "${x:-fallback}"
ok
% x=
% echo "${x:-fallback}"
fallback
% y=yvalue
% echo "${x:-$y}"
yvalue
Le site %x
Prompt-Escape-Code
Als nächstes werden wir Prompt-Escape-Codes einführen, eine Funktion, die es nur in zsh gibt. In zsh, %x
wird auf den Pfad der Datei erweitert, aber normalerweise ist dies nur bei der Erweiterung für Prompt-Zeichenfolgen . Um diese Codes in unserer Ersetzung zu aktivieren, können wir ein (%)
Flagge vor dem Variablennamen:
% cat apath/test.sh
fpath=%x
echo "${(%)fpath}"
% source apath/test.sh
apath/test.sh
% cd apath
% source test.sh
test.sh
Eine unwahrscheinliche Übereinstimmung: die prozentuale Flucht und der Fallback
Was wir bisher haben, funktioniert, aber es wäre ordentlicher, wenn wir die zusätzlichen fpath
variabel. Anstatt die %x
en fpath
können wir verwenden :-
und setzen %x
in der Fallback-Zeichenkette:
% cat test.sh
echo "${(%):-%x}"
% source test.sh
test.sh
Beachten Sie, dass wir normalerweise einen Variablennamen zwischen (%)
y :-
aber wir haben es leer gelassen. Die Variable mit einem leeren Namen kann nicht deklariert oder gesetzt werden, so dass der Fallback immer ausgelöst wird.
Zum Abschluss: Was ist mit print -P %x
?
Jetzt haben wir fast das Verzeichnis unseres Skripts. Wir hätten auch print -P %x
um denselben Dateipfad mit weniger Hacks zu erhalten, aber in unserem Fall, wo wir ihn als Argument an dirname
Das hätte den Aufwand erfordert, eine neue Unterschale zu starten:
% cat apath/test.sh
dirname "$(print -P %x)" # $(...) runs a command in a new process
dirname "${(%):-%x}"
% source apath/test.sh
apath
apath
Es hat sich herausgestellt, dass der umständliche Weg sowohl leistungsfähiger als auch prägnanter ist.
91 Stimmen
Keine der derzeitigen Lösungen funktioniert, wenn es irgendwelche Zeilenumbrüche am Ende des Verzeichnisnamens - Sie werden von der Befehlssubstitution entfernt. Um dies zu umgehen, können Sie ein Nicht-Neuzeilen-Zeichen innerhalb der Befehlsersetzung anhängen -
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd && echo x)"
- und entfernen Sie es ohne Befehlssubstitution -DIR="${DIR%x}"
.94 Stimmen
@jpmc26 Es gibt zwei sehr häufige Situationen: Unfälle und Sabotage. Ein Skript sollte nicht auf unvorhersehbare Weise versagen, nur weil jemand, irgendwo, eine
mkdir $'\n'
.36 Stimmen
Wer Leute sein System auf diese Weise sabotieren lässt, sollte es nicht der Bash überlassen, solche Probleme zu erkennen... und schon gar nicht Leute einstellen, die zu solchen Fehlern fähig sind. Ich habe in den 25 Jahren, in denen ich die Bash benutze, noch nie erlebt, dass so etwas irgendwo passiert.... Deshalb gibt es Dinge wie Perl und Praktiken wie Taint Checking (ich werde wahrscheinlich dafür geflamed werden, dass ich das sage :)
79 Stimmen
Ich empfehle Ihnen, dies zu lesen Bash FAQ über das Thema.
0 Stimmen
"${PWD%/}/application"