944 Stimmen

Zuverlässiger Weg für ein Bash-Skript, den vollständigen Pfad zu sich selbst zu erhalten

Ich habe ein Bash-Skript, das seinen vollständigen Pfad kennen muss. Ich versuche, einen weitgehend kompatiblen Weg zu finden, um das zu tun, ohne mit relativen oder komisch aussehenden Pfaden zu enden. Ich brauche nur Bash zu unterstützen, nicht sh, csh, etc.

Was ich bis jetzt herausgefunden habe:

  1. Die akzeptierte Antwort auf Abrufen des Quellverzeichnisses eines Bash-Skripts aus Adressen, die den Pfad des Skripts über dirname $0 was in Ordnung ist, aber das kann zu einem relativ Pfad (wie . ), was ein Problem darstellt, wenn Sie Verzeichnisse im Skript ändern und der Pfad weiterhin auf das Skriptverzeichnis verweisen soll. Trotzdem, dirname wird ein Teil des Puzzles sein.

  2. Die akzeptierte Antwort auf Absoluter Pfad eines Bash-Skripts unter OS X (OS X-spezifisch, aber die Antwort funktioniert trotzdem) gibt eine Funktion an, die prüft, ob $0 relativ aussieht und, falls dies der Fall ist, vorangestellt wird $PWD dazu. Aber das Ergebnis kann immer noch relative Bits enthalten (obwohl es insgesamt absolut ist) - zum Beispiel, wenn das Skript t im Verzeichnis /usr/bin und Sie sind in /usr und Sie geben ein bin/../bin/t um es auszuführen (ja, das ist verworren), landet man bei /usr/bin/../bin als Verzeichnispfad für das Skript. Welche Werke ...aber...

  3. Le site readlink Lösung auf dieser Seite die wie folgt aussieht:

    # Absolute path to this script. /home/user/bin/foo.sh
    SCRIPT=$(readlink -f $0)
    # Absolute path this script is in. /home/user/bin
    SCRIPTPATH=`dirname $SCRIPT`

    Aber readlink ist nicht POSIX und die Lösung beruht offenbar auf GNUs readlink wo BSDs aus irgendeinem Grund nicht funktionieren (ich habe keinen Zugang zu einem BSD-ähnlichen System, um das zu überprüfen).

Es gibt also verschiedene Möglichkeiten, die aber alle ihre Tücken haben.

Was wäre ein besserer Weg? Wobei "besser" bedeutet:

  • Das gibt mir den absoluten Pfad.
  • Entfernt störende Teile, selbst wenn sie auf komplizierte Weise aufgerufen werden (siehe Kommentar zu Nr. 2 oben). (Z.B. wird der Pfad zumindest mäßig kanonisiert.)
  • Bezieht sich nur auf Bash-ismen oder Dinge, die mit ziemlicher Sicherheit in den meisten gängigen Varianten von *nix-Systemen (GNU/Linux, BSD und BSD-ähnlichen Systemen wie OS X usw.) enthalten sind.
  • Vermeidet, wenn möglich, den Aufruf externer Programme (z.B. bevorzugt Bash built-ins).
  • ( Aktualisiert danke für die Vorwarnung, welche ) Es muss keine Symlinks auflösen (mir wäre es sogar lieber, wenn es sie in Ruhe ließe, aber das ist keine Voraussetzung).

819voto

T.J. Crowder Punkte 948310

Hier ist, was ich mir ausgedacht habe (edit: plus einige Änderungen, die von sfstewman , levigroker , Kyle Strand y Rob Kennedy ), die meine "besseren" Kriterien zu erfüllen scheinen:

SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"

Das SCRIPTPATH Linie scheint besonders umständlich zu sein, aber wir brauchen sie eher als SCRIPTPATH=`pwd` um Leerzeichen und Symlinks korrekt zu behandeln.

Die Einbeziehung der Ausgabeumlenkung ( >/dev/null 2>&1 ) behandelt den seltenen(?) Fall, dass cd eine Ausgabe erzeugen könnte, die die Umgebung stören würde $( ... ) einfangen. (Wie zum Beispiel cd überschrieben wird, um auch ls ein Verzeichnis nach der Umstellung auf diese Technologie).

Beachten Sie auch, dass esoterische Situationen, wie z. B. die Ausführung eines Skripts, das nicht aus einer Datei in einem zugänglichen Dateisystem stammt (was durchaus möglich ist), dort (oder in einer der anderen Antworten, die ich gesehen habe) nicht behandelt werden.

Le site -- nach cd und vor "$0" sind, wenn das Verzeichnis mit einem - .

395voto

Ich bin überrascht, dass die realpath Befehl wurde hier noch nicht erwähnt. Soweit ich weiß, ist er weitgehend portabel/portiert.

Ihre ursprüngliche Lösung wird:

SCRIPT=$(realpath "$0")
SCRIPTPATH=$(dirname "$SCRIPT")

Sie können symbolische Links nach Belieben unaufgelöst lassen:

SCRIPT=$(realpath -s "$0")
SCRIPTPATH=$(dirname "$SCRIPT")

225voto

Andrew Norrie Punkte 2149

Der einfachste Weg, den ich gefunden habe, um einen vollständigen kanonischen Pfad in der Bash zu erhalten, ist die Verwendung von cd y pwd :

ABSOLUTE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"

Verwendung von ${BASH_SOURCE[0]} anstelle von $0 erzeugt das gleiche Verhalten, unabhängig davon, ob das Skript als <name> o source <name> .

64voto

Felix Rabe Punkte 4046

Ich musste dieses Thema erst heute wieder aufgreifen und fand Abrufen des Quellverzeichnisses eines Bash-Skripts aus dem Skript selbst :

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

In der verlinkten Antwort gibt es weitere Varianten, z.B. für den Fall, dass das Skript selbst ein Symlink ist.

43voto

GreenFox Punkte 1102

Abrufen des absoluten Pfads eines Shell-Skripts

Sie verwendet nicht die -f Option in readlink, und es sollte daher unter BSD/Mac OS X funktionieren.

Unterstützt

  • source ./script (Beim Aufruf durch den . Punkt-Operator)
  • Absoluter Pfad /path/to/script
  • Relativer Pfad wie ./script
  • /pfad/dir1/../dir2/dir3/../script
  • Beim Aufruf von Symlink
  • Wenn Symlink verschachtelt ist z.B.) foo->dir1/dir2/bar bar->./../doe doe->script
  • Wenn der Anrufer den Namen des Skripts ändert

Ich suche nach Eckfällen, in denen dieser Code nicht funktioniert . Bitte lassen Sie es mich wissen.

Code

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
while([ -h "${SCRIPT_PATH}" ]); do
    cd "`dirname "${SCRIPT_PATH}"`"
    SCRIPT_PATH="$(readlink "`basename "${SCRIPT_PATH}"`")";
done
cd "`dirname "${SCRIPT_PATH}"`" > /dev/null
SCRIPT_PATH="`pwd`";
popd  > /dev/null
echo "srcipt=[${SCRIPT_PATH}]"
echo "pwd   =[`pwd`]"

Bekannter Emittent

Das Drehbuch muss irgendwo auf der Festplatte sein . Lassen Sie es über ein Netzwerk laufen. Wenn Sie versuchen, dieses Skript über eine PIPE auszuführen, wird es nicht funktionieren

wget -o /dev/null -O - http://host.domain/dir/script.sh |bash

Technisch gesehen ist sie undefiniert. Praktisch gesehen gibt es keine vernünftige Möglichkeit, dies zu erkennen. (Ein Co-Prozess kann nicht auf die Umgebung des Elternprozesses zugreifen.)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X