EINFÜHRUNG
Diese Antwort berichtigt die sehr kaputte, aber schockierenderweise meistgewählte Antwort dieses Threads (geschrieben von TheMarko):
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
WARUM FUNKTIONIERT DIE VERWENDUNG des Dirnamens "$0" ALS SELBSTVERSTÄNDLICHES NICHT?
Verzeichnisname $0 funktioniert nur, wenn der Benutzer das Skript auf eine ganz bestimmte Weise startet. Ich konnte mehrere Situationen finden, in denen diese Antwort fehlschlägt und das Skript abstürzt.
Zunächst einmal sollten wir verstehen, wie diese Antwort funktioniert. Er erhält das Skriptverzeichnis, indem er
dirname "$0"
$0 steht für den ersten Teil des Befehls, der das Skript aufruft (es ist im Grunde der eingegebene Befehl ohne die Argumente:
/some/path/./script argument1 argument2
$0="/some/path/./script"
dirname findet grundsätzlich das letzte / in einer Zeichenkette und schneidet es dort ab. Wenn Sie also tun:
dirname /usr/bin/sha256sum
erhalten Sie: /usr/bin
Dieses Beispiel funktioniert gut, weil /usr/bin/sha256sum ein korrekt formatierter Pfad ist, aber
dirname "/some/path/./script"
würde nicht gut funktionieren und zu Problemen führen:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
Angenommen, Sie befinden sich im gleichen Verzeichnis wie Ihr Skript und starten es mit folgendem Befehl
./script
$0 ist in diesem Fall ./script und dirname $0 ergibt:
. #or BASEDIR=".", again this will crash your script
Verwenden:
sh script
Ohne Eingabe des vollständigen Pfades wird auch BASEDIR="." ausgegeben.
Verwendung relativer Verzeichnisse:
../some/path/./script
Gibt einen Dirnamen $0 von:
../some/path/.
Wenn Sie sich im Verzeichnis /some befinden und das Skript auf diese Weise aufrufen (beachten Sie das Fehlen von / am Anfang, wieder ein relativer Pfad):
path/./script.sh
Sie erhalten diesen Wert für dirname $0:
path/.
und ./path/./script (eine andere Form des relativen Pfads) ergibt:
./path/.
Die einzigen beiden Situationen, in denen basedir $0 funktioniert, wenn der Benutzer sh oder touch verwendet, um ein Skript zu starten, da beide zu $0 führen:
$0=/some/path/script
was Ihnen einen Pfad liefert, den Sie mit dirname verwenden können.
DIE LÖSUNG
Sie müssen jede der oben genannten Situationen berücksichtigen und erkennen und eine Lösung für sie finden, wenn sie auftritt:
#!/bin/bash
#this script will only work in bash, make sure it's installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "\$0=$0";fi
#The line below detect script's parent directory. $0 is the part of the launch command that doesn't contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo 'BASEDIR=$(dirname "$0") gives: '"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi
15 Stimmen
Ist das wirklich ein Duplikat? In dieser Frage geht es um ein "Unix-Shell-Skript", in der anderen speziell um Bash.
3 Stimmen
@BoltClock: Diese Frage wurde fälschlicherweise geschlossen. In der verlinkten Frage geht es um Bash. In dieser Frage geht es um Unix-Shell-Programmierung. Beachten Sie, dass die akzeptierten Antworten sehr unterschiedlich sind!
0 Stimmen
@Dietrich Epp: Sie haben Recht. Es scheint, dass die Wahl der akzeptierten Antwort durch den Fragesteller und die Hinzufügung des [bash]-Tags (wahrscheinlich als Reaktion darauf) mich dazu veranlasst hat, die Frage als Antwort auf eine Markierung als Duplikat zu kennzeichnen.
3 Stimmen
Ich denke, diese Antwort ist besser: Abrufen des Quellverzeichnisses eines Bash-Skripts aus einer
2 Stimmen
Mögliches Duplikat von Abrufen des Quellverzeichnisses eines Bash-Skripts aus
1 Stimmen
Google brachte mich hierher, da ich nach einer reinen Posix-Implementierung der Lösung suchte. Nach etwas mehr Suche stieß ich auf diese sehr ausführliche Antwort, die erklärt, warum es nicht geht und wie man es umgehen kann, indem man die Unterstützung für gängige Shells shimmt. stackoverflow.com/a/29835459/816584
0 Stimmen
Kann die Ausgabe des Befehls "pwd" nicht zu Beginn des Skripts einer Variablen zugewiesen werden, die dann während des gesamten Skripts verwendet wird? Ich bin mir nicht sicher, ob ich die Frage richtig verstanden habe