Finden Sie den absoluten Pfad aus einem Skript

10

In einem Skript komme ich auf $0den möglichen relativen Pfad dazu. Um es in absolut umzuwandeln, habe ich diese Lösung gefunden, die ich nicht verstehe:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

Mein Problem ist die Magie in ${0%/*}und ${0##*/}. Es sieht so aus, als ob der erstere den Verzeichnisnamen und der letztere den Dateinamen extrahiert. Ich verstehe nur nicht, wie.

Maaartinus
quelle
2
Das nutzt die Parametererweiterung, hat aber bei mir nicht funktioniert. Wenn Ihr Skript nur unter Linux verwendet werden soll, können readlink -f $0Sie den kanonischen Pfad abrufen.
Shawn J. Goff
1
@Shawn: 1 großartige Kommentarabstimmung, weil Sie das richtige Denken eingeführt haben: "Das nutzt die Parametererweiterung, aber es hat bei mir nicht funktioniert". Das dirnameutil ist hier nützlich.
D4RIO
mywiki.wooledge.org/BashFAQ/028 und cyberciti.biz/faq/… sagen, es BASH_SOURCEsei besser als $0, da $0der eingegebene Befehl des Benutzers angegeben wird, der möglicherweise nicht das aktuell ausgeführte Skript ist.
Joel Purra

Antworten:

8

Definitionen:

${string%substring} löscht die kürzeste Übereinstimmung $substringvon am Ende von $string.

${string##substring}löscht die längste Übereinstimmung von $substringAnfang an $string.

Ihr Beispiel:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

${0%/*} löscht alles nach dem letzten Schrägstrich und gibt Ihnen den Verzeichnisnamen des Skripts (möglicherweise ein relativer Pfad).

${0##*/} löscht alles bis zum letzten Schrägstrich und gibt nur den Namen des Skripts an.

Dieser Befehl wechselt also in das Verzeichnis des Skripts und verkettet das aktuelle Arbeitsverzeichnis (angegeben durch $PWD) und den Namen des Skripts, wobei Sie den absoluten Pfad angeben .

Um zu sehen, was los ist, versuchen Sie:

echo ${0%/*}
echo ${0##*/}
Dogbane
quelle
Fügen Sie doppelte Anführungszeichen um alle Variablenerweiterungen hinzu, um mit (fast allen) Dateinamen umzugehen, die Shell-Sonderzeichen enthalten.
Gilles 'SO - hör auf böse zu sein'
10

Shawn hatte die einfachste Lösung : readlink -f $0. Wenn Sie absolut sicher sein möchten, mit seltsamen Dateinamen umzugehen, können Sie Folgendes verwenden:

absolute_path_x="$(readlink -fn -- "$0"; echo x)"
absolute_path="${absolute_path_x%x}"

Dokumentation

l0b0
quelle
1
Gut zu sehen, dass die endgültigen Zeilenumbrüche korrekt behandelt werden. Leider readlink -fnist spezifisch für Linux, NetBSD und OpenBSD.
Gilles 'SO - hör auf böse zu sein'
4

Hier ist eine sicherere und besser lesbare Möglichkeit, diesen Job zu erledigen:

abspath=$(unset CDPATH && cd "$(dirname "$0")" && echo $PWD/$(basename "$0"))

Anmerkungen:

  • Wenn $0es sich um einen bloßen Dateinamen ohne vorhergehenden Pfad handelt, schlägt das ursprüngliche Skript fehl, aber der hier angegebene funktioniert. (Kein Problem mit $0, könnte aber in anderen Anwendungen sein.)
  • Beide Ansätze schlagen fehl, wenn der Pfad zur Datei nicht vorhanden ist. (Kein Problem mit $0, könnte aber in anderen Anwendungen sein.)
  • Dies unsetist wichtig, wenn Ihr Benutzer möglicherweise CDPATHeingestellt hat.
  • Im Gegensatz zu readlink -foder realpathfunktioniert dies unter Nicht-Linux-Versionen von Unix (z. B. Mac OS X).
Matthias Fripp
quelle
2

Wenn Sie die Shell-Parametererweiterung lernen möchten, können Sie sie hier lesen , aber die Erweiterung ist nicht immer eine gute Wahl. In diesem Fall verfügt fast jedes Unix-ähnliche System über zwei gute Dienstprogramme:

basename
dirname

Der erste extrahiert den Dateinamen, während der zweite den Pfad extrahiert. Wenn Sie also $ 0 haben, sagen Sie:

dirname $0

Und du wirst den Weg bekommen.

Prost

D4RIO
quelle
dirname kann relative Pfade zurückgeben
opticyclic
0

Wir stellen vor: pwd, die eingebaute Bash. Auch im GNU Coreutils-Paket enthalten.

$ sh ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
$0: ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
cheeky binary from /home/jaroslav/tmp (/home/jaroslav/tmp)

$ cat /home/jaroslav/tmp/somewhere.sh

abs=$( cd `dirname "$0"` ; pwd -P)
absBin=$( cd `dirname "$0"` ; /bin/pwd -P)
echo \$0: $0
echo cheeky binary from $abs \($absBin\)
Ярослав Рахматуллин
quelle