In den meisten Fällen $0
wird ein Pfad enthalten, absolut oder relativ zum Skript, also
script_path=$(readlink -e -- "$0")
(vorausgesetzt, es gibt einen readlink
Befehl, der unterstützt wird -e
) ist im Allgemeinen ein guter Weg, um den kanonischen absoluten Pfad zum Skript zu erhalten.
$0
wird aus dem Argument zugewiesen, das das an den Interpreter übergebene Skript angibt.
Zum Beispiel in:
the-shell -shell-options the/script its args
$0
bekommt the/script
.
Wenn Sie laufen:
the/script its args
Ihre Shell wird Folgendes tun:
exec("the/script", ["the/script", "its", "args"])
Wenn das Skript #! /bin/sh -
zum Beispiel einen Knall enthält , wandelt das System diesen um in:
exec("/bin/sh", ["/bin/sh" or "the/script", "-", "the/script", "its", "args"])
(Wenn es keinen She-Bang enthält oder allgemeiner, wenn das System einen ENOEXEC-Fehler zurückgibt, dann ist es Ihre Shell, die dasselbe tut)
Es gibt eine Ausnahme für setuid / setgid-Skripte auf einigen Systemen, bei denen das System das Skript auf einigen Systemen öffnet fd
x
und stattdessen ausführt:
exec("/bin/sh", ["/bin/sh" or "the/script", "-", "/dev/fd/x", "its", "args"])
um Rennbedingungen zu vermeiden (in diesem Fall $0
wird enthalten /dev/fd/x
).
Nun kann man argumentieren , dass /dev/fd/x
ist ein Pfad zu diesem Skript. Beachten Sie jedoch, dass Sie beim Lesen $0
das Skript unterbrechen, wenn Sie die Eingabe verwenden.
Jetzt gibt es einen Unterschied, wenn der aufgerufene Skriptbefehlsname keinen Schrägstrich enthält. Im:
the-script its args
Shell wird aufblicken the-script
in $PATH
. $PATH
kann absolute oder relative Pfade (einschließlich der leeren Zeichenfolge) zu einigen Verzeichnissen enthalten. Wenn beispielsweise das aktuelle Verzeichnis $PATH
enthält /bin:/usr/bin:
und the-script
gefunden wird, führt die Shell Folgendes aus:
exec("the-script", ["the-script", "its", "args"])
was wird werden:
exec("/bin/sh", ["/bin/sh" or "the-script", "-", "the-script", "its", "args"]
Oder wenn es gefunden wird in /usr/bin
:
exec("/usr/bin/the-script", ["the-script", "its", "args"])
exec("/bin/sh", ["/bin/sh" or "the-script" or "/usr/bin/the-script",
"-", "/usr/bin/the-script", "its", "args")
In allen oben genannten Fällen mit Ausnahme des Falles setuid Corner $0
wird ein Pfad (absolut oder relativ) zum Skript enthalten.
Ein Skript kann jetzt auch wie folgt aufgerufen werden:
the-interpreter the-script its args
Wenn the-script
wie oben keine Schrägstriche enthalten sind, variiert das Verhalten geringfügig von Shell zu Shell.
Alte AT & T- ksh
Implementierungen haben das Skript tatsächlich bedingungslos nachgeschlagen $PATH
(was eigentlich ein Fehler und eine Sicherheitslücke für Setuid-Skripte war) und $0
enthielten daher keinen Pfad zum Skript, es sei denn, die $PATH
Suche wurde tatsächlich the-script
im aktuellen Verzeichnis gefunden.
Neuere AT & T ksh
würden versuchen, the-script
im aktuellen Verzeichnis zu interpretieren, wenn es lesbar ist. Wenn nicht, würde es nach einer lesbaren und ausführbaren Datei the-script
in suchen$PATH
.
Denn bash
es prüft, ob the-script
es sich im aktuellen Verzeichnis befindet (und kein defekter Symlink ist), und wenn nicht, sucht es nach einem lesbaren (nicht unbedingt ausführbaren) the-script
in $PATH
.
zsh
in sh
Emulation würde gerne tun, bash
außer dass, wenn the-script
ein defekter Symlink im aktuellen Verzeichnis ist, es nicht nach einem the-script
In suchen $PATH
würde und stattdessen einen Fehler melden würde.
Alle anderen Bourne-ähnlichen Muscheln sehen nicht the-script
auf $PATH
.
Wenn Sie bei all diesen Shells feststellen, dass $0
sie kein a enthalten /
und nicht lesbar sind, wurde sie wahrscheinlich nachgeschlagen $PATH
. Da Dateien in $PATH
wahrscheinlich ausführbar sind, ist es wahrscheinlich eine sichere Annäherung, command -v -- "$0"
um den Pfad zu finden (obwohl dies nicht funktionieren würde, wenn $0
zufällig auch der Name einer eingebauten Shell oder eines Schlüsselworts (in den meisten Shells) verwendet wird).
Wenn Sie diesen Fall wirklich abdecken möchten, können Sie ihn schreiben:
progname=$0
[ -r "$progname" ] || progname=$(
IFS=:; set -f
for i in ${PATH-$(getconf PATH)}""; do
case $i in
"") p=$progname;;
*/) p=$i$progname;;
*) p=$i/$progname
esac
[ -r "$p" ] && exec printf '%s\n' "$p"
done
exit 1
) && progname=$(readlink -e -- "$progname") ||
progname=unknown
(Das ""
angehängte $PATH
Element besteht darin, ein nachfolgendes leeres Element mit Schalen $IFS
beizubehalten, die als Trennzeichen anstelle des Trennzeichens fungieren .)
Jetzt gibt es esoterischere Möglichkeiten, ein Skript aufzurufen. Man könnte tun:
the-shell < the-script
Oder:
cat the-script | the-shell
In diesem Fall ist $0
dies das erste Argument ( argv[0]
), das der Interpreter erhalten hat (oben the-shell
, aber das kann alles sein, obwohl im Allgemeinen entweder der Basisname oder ein Pfad zu diesem Interpreter).
Es $0
ist nicht zuverlässig zu erkennen, dass Sie sich in dieser Situation befinden, basierend auf dem Wert von . Sie können sich die Ausgabe von ansehen ps -o args= -p "$$"
, um einen Hinweis zu erhalten. Im Pipe-Fall gibt es keine echte Möglichkeit, zu einem Pfad zum Skript zurückzukehren.
Man könnte auch tun:
the-shell -c '. the-script' blah blih
Dann, es sei denn zsh
(und einige alte Implementierung der Bourne - Shell), $0
wäre blah
. Auch hier ist es schwierig, in diesen Shells zum Pfad des Skripts zu gelangen.
Oder:
the-shell -c "$(cat the-script)" blah blih
etc.
Um sicherzustellen, dass Sie das Recht haben $progname
, können Sie nach einer bestimmten Zeichenfolge suchen:
progname=$0
[ -r "$progname" ] || progname=$(
IFS=:; set -f
for i in ${PATH-$(getconf PATH)}:; do
case $i in
"") p=$progname;;
*/) p=$i$progname;;
*) p=$i/$progname
esac
[ -r "$p" ] && exec printf '%s\n' "$p"
done
exit 1
) && progname=$(readlink -e -- "$progname") ||
progname=unknown
[ -f "$progname" ] && grep -q 7YQLVVD3UIUDTA32LSE8U9UOHH < "$progname" ||
progname=unknown
Aber ich denke auch nicht, dass es die Mühe wert ist.
$0
etwas anderes als das Skript ist, das den Fragentitel beantwortet. Ich interessiere mich jedoch auch für Situationen, in denen$0
sich das Skript selbst befindet, das Verzeichnis jedoch nicht enthält. Insbesondere versuche ich, den Kommentar zur SO-Antwort zu verstehen.