In den meisten Fällen $0wird ein Pfad enthalten, absolut oder relativ zum Skript, also
script_path=$(readlink -e -- "$0")
(vorausgesetzt, es gibt einen readlinkBefehl, 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
$0bekommt 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 xund stattdessen ausführt:
exec("/bin/sh", ["/bin/sh" or "the/script", "-", "/dev/fd/x", "its", "args"])
um Rennbedingungen zu vermeiden (in diesem Fall $0wird 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 $0das 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-scriptin $PATH. $PATHkann absolute oder relative Pfade (einschließlich der leeren Zeichenfolge) zu einigen Verzeichnissen enthalten. Wenn beispielsweise das aktuelle Verzeichnis $PATHenthält /bin:/usr/bin:und the-scriptgefunden 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 $0wird 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-scriptwie oben keine Schrägstriche enthalten sind, variiert das Verhalten geringfügig von Shell zu Shell.
Alte AT & T- kshImplementierungen haben das Skript tatsächlich bedingungslos nachgeschlagen $PATH(was eigentlich ein Fehler und eine Sicherheitslücke für Setuid-Skripte war) und $0enthielten daher keinen Pfad zum Skript, es sei denn, die $PATHSuche wurde tatsächlich the-scriptim aktuellen Verzeichnis gefunden.
Neuere AT & T kshwürden versuchen, the-scriptim 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 bashes prüft, ob the-scriptes sich im aktuellen Verzeichnis befindet (und kein defekter Symlink ist), und wenn nicht, sucht es nach einem lesbaren (nicht unbedingt ausführbaren) the-scriptin $PATH.
zshin shEmulation würde gerne tun, bashaußer dass, wenn the-scriptein defekter Symlink im aktuellen Verzeichnis ist, es nicht nach einem the-scriptIn suchen $PATHwürde und stattdessen einen Fehler melden würde.
Alle anderen Bourne-ähnlichen Muscheln sehen nicht the-scriptauf $PATH.
Wenn Sie bei all diesen Shells feststellen, dass $0sie kein a enthalten /und nicht lesbar sind, wurde sie wahrscheinlich nachgeschlagen $PATH. Da Dateien in $PATHwahrscheinlich 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 $0zufä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 $PATHElement besteht darin, ein nachfolgendes leeres Element mit Schalen $IFSbeizubehalten, 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 $0dies 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 $0ist 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), $0wä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.
$0etwas anderes als das Skript ist, das den Fragentitel beantwortet. Ich interessiere mich jedoch auch für Situationen, in denen$0sich das Skript selbst befindet, das Verzeichnis jedoch nicht enthält. Insbesondere versuche ich, den Kommentar zur SO-Antwort zu verstehen.