6176 Stimmen

Wie kann ich das Quellverzeichnis eines Bash-Skripts aus dem Skript selbst abrufen?

Wie erhalte ich den Pfad des Verzeichnisses, in dem ein Bash Skript befindet sich, innerhalb dieses Drehbuch?

Ich möchte ein Bash-Skript als Launcher für eine andere Anwendung verwenden. Ich möchte das Arbeitsverzeichnis in das Verzeichnis ändern, in dem sich das Bash-Skript befindet, damit ich mit den Dateien in diesem Verzeichnis arbeiten kann:

$ ./application

91 Stimmen

Keine der derzeitigen Lösungen funktioniert, wenn es irgendwelche Zeilenumbrüche am Ende des Verzeichnisnamens - Sie werden von der Befehlssubstitution entfernt. Um dies zu umgehen, können Sie ein Nicht-Neuzeilen-Zeichen innerhalb der Befehlsersetzung anhängen - DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd && echo x)" - und entfernen Sie es ohne Befehlssubstitution - DIR="${DIR%x}" .

94 Stimmen

@jpmc26 Es gibt zwei sehr häufige Situationen: Unfälle und Sabotage. Ein Skript sollte nicht auf unvorhersehbare Weise versagen, nur weil jemand, irgendwo, eine mkdir $'\n' .

36 Stimmen

Wer Leute sein System auf diese Weise sabotieren lässt, sollte es nicht der Bash überlassen, solche Probleme zu erkennen... und schon gar nicht Leute einstellen, die zu solchen Fehlern fähig sind. Ich habe in den 25 Jahren, in denen ich die Bash benutze, noch nie erlebt, dass so etwas irgendwo passiert.... Deshalb gibt es Dinge wie Perl und Praktiken wie Taint Checking (ich werde wahrscheinlich dafür geflamed werden, dass ich das sage :)

19voto

Ich habe sie alle ausprobiert, aber keine hat funktioniert. Eines war sehr nahe dran, aber es hatte einen kleinen Fehler, der es kaputt machte; sie vergaßen, den Pfad in Anführungszeichen zu setzen.

Außerdem gehen viele Leute davon aus, dass Sie das Skript von einer Shell aus starten, und vergessen dabei, dass beim Öffnen eines neuen Skripts standardmäßig Ihr Heimatverzeichnis verwendet wird.

Probieren Sie dieses Verzeichnis einmal aus:

/var/No one/Thought/About Spaces Being/In a Directory/Name/And Here's your file.text

Damit wird es richtig gemacht, egal wie oder wo Sie es ausführen:

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename "$0"`"
echo "dirname: `dirname "$0"`"

Um es also wirklich nützlich zu machen, wechseln Sie in das Verzeichnis des laufenden Skripts:

cd "`dirname "$0"`"

4 Stimmen

Funktioniert nicht, wenn das Skript von einem anderen Skript bezogen wird.

0 Stimmen

Dies funktioniert nicht, wenn der letzte Teil von $0 ein symbolischer Link ist, der auf einen Eintrag in einem anderen Verzeichnis zeigt ( ln -s ../bin64/foo /usr/bin/foo ).

18voto

Fuwjax Punkte 2197

Dies ist eine leichte Überarbeitung der Lösung, auf die e-satis und 3bcdnlklvc04a in ihre Antwort :

SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
    SCRIPT_DIR="$PWD"
    popd > /dev/null
}

Dies sollte in allen aufgeführten Fällen immer noch funktionieren.

Damit wird verhindert, dass popd nach einem gescheiterten pushd . Danke an konsolebox.

0 Stimmen

Dies funktioniert perfekt, um den "echten" Verzeichnisnamen zu erhalten, und nicht nur den Namen eines Symlinks. Ich danke Ihnen!

1 Stimmen

Besser SCRIPT_DIR=''; pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && { SCRIPT_DIR=$PWD; popd > /dev/null; }

0 Stimmen

@konsolebox, wogegen wollen Sie sich verteidigen? Ich bin im Allgemeinen ein Fan des Inlinings logischer Konditionale, aber was war der spezifische Fehler, den Sie in der pushd gesehen haben? Ich würde lieber einen Weg finden, ihn direkt zu behandeln, anstatt ein leeres SCRIPT_DIR zurückzugeben.

17voto

Nicolas Punkte 133

Ich würde etwa so vorgehen:

# Retrieve the full pathname of the called script
scriptPath=$(which $0)

# Check whether the path is a link or not
if [ -L $scriptPath ]; then

    # It is a link then retrieve the target path and get the directory name
    sourceDir=$(dirname $(readlink -f $scriptPath))

else

    # Otherwise just get the directory name of the script path
    sourceDir=$(dirname $scriptPath)

fi

0 Stimmen

Das ist der echte! Funktioniert mit einfachen sh auch! Problem mit einfachen dirname "$0" basierte Lösungen: Wenn sich das Skript in der $PATH und ohne Pfad aufgerufen wird, werden sie ein falsches Ergebnis liefern.

0 Stimmen

@Notinlist Nicht so. Wenn das Skript über die PATH , $0 enthält den absoluten Dateinamen. Wenn das Skript mit einem relativen oder absoluten Dateinamen aufgerufen wird, der ein / , $0 wird das enthalten.

17voto

user1338062 Punkte 10425

Für Systeme mit GNU coreutils readlink (zum Beispiel Linux):

$(readlink -f "$(dirname "$0")")

Es ist nicht nötig, die BASH_SOURCE cuando $0 enthält den Dateinamen des Skripts.

4 Stimmen

Es sei denn, das Skript wurde mit . oder 'source' aufgerufen; in diesem Fall ist es immer noch das Skript, von dem es stammt, oder, wenn es von der Befehlszeile kommt, '-bash' (tty-Login) oder 'bash' (aufgerufen über 'bash -l') oder '/bin/bash' (aufgerufen als interaktive Nicht-Login-Shell)

0 Stimmen

Ich habe ein zweites Paar Anführungszeichen um dirname anrufen. Wird benötigt, wenn der Verzeichnispfad Leerzeichen enthält.

14voto

hurrymaplelad Punkte 25235

$_ ist erwähnenswert als Alternative zu $0 . Wenn Sie ein Skript von der Bash aus ausführen, kann die akzeptierte Antwort auf verkürzt werden:

DIR="$( dirname "$_" )"

Beachten Sie, dass dies die erste Anweisung in Ihrem Skript sein muss.

4 Stimmen

Es bricht, wenn Sie source o . das Drehbuch. In solchen Situationen, $_ würde den letzten Parameter des letzten Befehls enthalten, den Sie vor dem . . $BASH_SOURCE funktioniert jedes Mal.

0 Stimmen

Dies ist Perl -like! Ein Zufall?

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