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).

13voto

Stormcloud Punkte 1943

Ich beantworte diese Frage sehr spät, aber ich benutze:

SCRIPT=$( readlink -m $( type -p ${0} ))      # Full path to script handling Symlinks
BASE_DIR=`dirname "${SCRIPT}"`                # Directory script is run in
NAME=`basename "${SCRIPT}"`                   # Actual name of script even if linked

8voto

AsymLabs Punkte 863

Wir haben unser eigenes Produkt platziert realpath-lib auf GitHub zur freien und unbelasteten Nutzung durch die Gemeinschaft.

Unverschämte Werbung, aber mit dieser Bash-Bibliothek können Sie:

get_realpath <absolute|relative|symlink|local file>

Diese Funktion ist das Herzstück der Bibliothek:

function get_realpath() {

if [[ -f "$1" ]]
then 
    # file *must* exist
    if cd "$(echo "${1%/*}")" &>/dev/null
    then 
        # file *may* not be local
        # exception is ./file.ext
        # try 'cd .; cd -;' *works!*
        local tmppwd="$PWD"
        cd - &>/dev/null
    else 
        # file *must* be local
        local tmppwd="$PWD"
    fi
else 
    # file *cannot* exist
    return 1 # failure
fi

# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success

}

Es benötigt keine externen Abhängigkeiten, nur Bash 4+. Enthält auch Funktionen für get_dirname , get_filename , get_stemname y validieren_pfad validate_realpath . Es ist kostenlos, sauber, einfach und gut dokumentiert, so dass es auch für Lernzwecke verwendet werden kann und zweifellos verbessert werden kann. Probieren Sie es plattformübergreifend aus.

Update: Nach einigen Überarbeitungen und Tests haben wir die obige Funktion durch etwas ersetzt, das das gleiche Ergebnis erzielt (ohne Verwendung von dirname, nur reine Bash), aber mit besserer Effizienz:

function get_realpath() {

    [[ ! -f "$1" ]] && return 1 # failure : file does not exist.
    [[ -n "$no_symlinks" ]] && local pwdp='pwd -P' || local pwdp='pwd' # do symlinks.
    echo "$( cd "$( echo "${1%/*}" )" 2>/dev/null; $pwdp )"/"${1##*/}" # echo result.
    return 0 # success

}

Dazu gehört auch eine Umgebungseinstellung no_symlinks die die Möglichkeit bietet, Symlinks zum physischen System aufzulösen. In der Standardeinstellung bleiben Symlinks intakt.

4voto

Haruo Kinoshita Punkte 85

Bourne-Shell ( sh ) konforme Weise:

SCRIPT_HOME=`dirname $0 | while read a; do cd $a && pwd && break; done`

4voto

AsymLabs Punkte 863

Noch einmal zu diesem Thema: Es gibt eine sehr populäre Lösung, auf die in diesem Thread verwiesen wird und die ihren Ursprung hat aquí :

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

Ich habe mich wegen der Verwendung von dirname von dieser Lösung ferngehalten - sie kann plattformübergreifende Schwierigkeiten mit sich bringen, insbesondere wenn ein Skript aus Sicherheitsgründen gesperrt werden muss. Aber wie wäre es mit einer reinen Bash-Alternative, wie wäre es mit der Verwendung von:

DIR="$( cd "$( echo "${BASH_SOURCE[0]%/*}" )" && pwd )"

Wäre dies eine Möglichkeit?

4voto

Nordlöw Punkte 11309

Wenn wir die Bash verwenden, ist dies meiner Meinung nach der bequemste Weg, da er keine Aufrufe externer Befehle erfordert:

THIS_PATH="${BASH_SOURCE[0]}";
THIS_DIR=$(dirname $THIS_PATH)

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