Verweisen Sie auf eine Datei in demselben Verzeichnis eines Skripts, das sich in $ PATH befindet

33

Ich habe eine Bash-Skript-Datei, die unter einem Verzeichnis abgelegt wird, das zu $ ​​PATH hinzugefügt wurde, damit ich das Skript von einem beliebigen Verzeichnis aus aufrufen kann.

Es gibt eine andere Textdatei im selben Verzeichnis wie das Skript. Ich frage mich, wie ich auf die Textdatei im Skript verweisen soll.

Wenn das Skript beispielsweise nur den Inhalt der Textdatei ausgeben soll, cat textfilefunktioniert dies nicht, da die Textdatei beim Aufrufen des Skripts aus einem anderen Verzeichnis nicht gefunden wird.

Tim
quelle
Kürzlich ist hier ein verwandtes Problem aufgetaucht: Ermittelt den Pfad des aktuellen Skripts, wenn es über einen Symlink ausgeführt wird
Caleb,
Diese Frage beantwortet, wie man einen Bash-Skript-Dateipfad zuverlässig erhält. Ich habe das zu meinem Pfad hinzugefügt: stackoverflow.com/q/4774054/1695680
ThorSummoner

Antworten:

24

Diese sollten genauso funktionieren, solange keine Symlinks vorhanden sind (in der Pfaderweiterung oder im Skript selbst):

  • MYDIR="$(dirname "$(realpath "$0")")"

  • MYDIR="$(dirname "$(which "$0")")"

  • Eine zweistufige Version eines der oben genannten:

    MYSELF="$(realpath "$0")"

    MYDIR="${MYSELF%/*}"

Wenn sich auf dem Weg zu Ihrem Skript ein Symlink befindet, erhalten Sie whicheine Antwort, in der die Auflösung dieses Links nicht enthalten ist. Wenn realpathes nicht standardmäßig auf Ihrem System installiert ist, finden Sie es hier .

[BEARBEITEN]: Da es realpathkeinen Vorteil gegenüber readlink -f Caleb gibt , ist es wahrscheinlich besser, Letzteres zu verwenden. Meine Timing-Tests zeigen, dass es tatsächlich schneller ist.

rozcietrzewiacz
quelle
Kein Problem. Übrigens, wo kommt realpathdas auf deinem System her? (Für andere, die es nicht haben, können Sie verwendenreadlink -f
Caleb
@Caleb Eigentlich dachte ich, dass es zu den Standard-GNU-Dienstprogrammen (coreutils) gehört, aber jetzt sehe ich, dass es sich um ein separates Paket handelt .
Rozcietrzewiacz
@rozcietrzewiacz realpathstammt aus der Zeit vor readlink -f(und sogar readlinkIIRC) als GNU-Coreutils (es gab mehrere ähnliche Tools). Wurde readlink -fschließlich zum De-facto-Standard. realpathwird nur aus Kompatibilitätsgründen mit Skripten aufbewahrt, die es noch verwenden.
Gilles 'SO - hör auf, böse zu sein'
Was ist der Vorteil $(dirname "$(which "$0")")gegenüber $(dirname $0)wo das whichnicht mehr vorhanden ist? Ist es nicht dasselbe?
UlfR
readlink -fscheint nicht unter Mac OS X 10.11.6 zu funktionieren, realpathfunktioniert aber sofort .
Grav
9

Meine Systeme haben nicht realpathwie von rozcietrzewiacz vorgeschlagen .

Sie können dies mit dem readlinkBefehl ausführen. Der Vorteil gegenüber dem Parsen whichoder anderen Lösungen besteht darin, dass Sie auch dann das Verzeichnis finden können, in dem sich die eigentliche Datei befindet, wenn ein Teil des ausgeführten Pfads oder Dateinamens ein Symlink ist.

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

Ihre Textdatei könnte dann in eine Variable wie diese eingelesen werden:

TEXTFILE="$(<$MYDIR/textfile)"
Caleb
quelle
@rozcietrzewiacz: Ich habe mich eigentlich nicht nur auf Ihren whichVorschlag bezogen. Die normale Lösung hierfür ist entweder nur dirnameoder eine Kombination von cdund pwdin einer Unterschale. Readlink hat hier den Vorteil. realpathscheint so ziemlich nur eine Verpackung für readlink -fsowieso zu sein.
Caleb
Ich weiß nicht, wie realpathsich das unterscheidet readlink -f. Ich kann nur sehen, dass es mir die gleichen Ergebnisse liefert (im Gegensatz zu which).
rozcietrzewiacz
Denken Sie daran, dass readlink -f(von GNU coreutils) NICHT das letzte Element des Pfades benötigt, das vorhanden ist, readlink -edies aber nicht unterstützt busybox readlink, was das Verhalten -ein ihrer -fOption nachahmt .
dragon788
8

$0Im Skript wird der vollständige Pfad zum Skript angegeben, und es dirnamewird ein vollständiger Pfad angegeben, in dem nur das Verzeichnis angegeben wird. Sie können also folgendermaßen vorgehen, um eine Katzentextdatei zu erstellen:

$ cat "$(dirname -- "$0")/textfile"
Michael Mrozek
quelle
Während dies ohne zu funktionieren scheint realpath $0, sind Sie falsch zu sagen, dass " $0im Skript der vollständige Pfad zum Skript sein wird".
Rozcietrzewiacz
@roz Inwiefern?
Michael Mrozek
1
$0ist der befehl wie er ausgeführt wurde, das kann zb ../script.sh.
Rozcietrzewiacz
Gibt also tatsächlich $(dirname "$0")den relativen Pfad zum Skript als Teil des aufgerufenen Befehls zurück - nicht den absoluten Pfad. Dies kann zu Problemen in Skripten führen, bei denen die Verzeichnisse während der Ausführung geändert werden.
rozcietrzewiacz
@roz Ah, interessant. Ich denke, es würde hier kein Problem verursachen, da er etwas auf dem Weg beim Namen nennt, aber es würde andere Dinge zerstören. Danke
Michael Mrozek
4

Sie können dies oben in Ihr Skript einfügen:

cd "${BASH_SOURCE%/*}" || exit

Die interne bash-Variable BASH_SOURCE ist eigentlich ein Array von Pfadnamen. Wenn Sie es als einfache Zeichenfolge erweitern, z. B. "$ BASH_SOURCE", erhalten Sie das erste Element, das der Pfadname der aktuell ausgeführten Funktion oder des aktuell ausgeführten Skripts ist.

Quelle: http://mywiki.wooledge.org/BashFAQ/028

David Kennedy
quelle
2

Ich habe das ausprobiert und realpath hat bei mir nicht funktioniert. Die Lösung, die ich gewählt habe, ist:

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

Welches hat bisher gut funktioniert. Ich würde gerne wissen, ob es irgendwelche potenziellen Probleme mit dem Ansatz gibt.

Brettski
quelle
1
Gut, aber folgt keinen Symlinks. Versuchen Sie SCRIPT_DIR="$( cd "$(dirname "$( readlink -f ${BASH_SOURCE[0]} )")" >/dev/null 2>&1 && pwd)"
Folgendes
1

Ich benutze:

#! /bin/sh -
dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P) || exit
dosomethingwith "${dir%/}/some-file"

Was POSIX ist und funktionieren sollte, solange der Verzeichnisname von $0nicht mit Zeilenumbrüchen endet, ist -und $CDPATHwird nicht gesetzt (und möglicherweise ein paar andere Eckfälle, wenn das Skript nicht nachgeschlagen wurde $PATH).

Stéphane Chazelas
quelle
0

Ich benutze immer which, um den vollständigen Pfad einer ausführbaren Datei aus dem Pfad zu finden. Zum Beispiel:

which python

Wenn Sie dies mit dem dirnameBefehl kombinieren, erhalten Sie:

wp=`which python`
dn=`dirname $wp`
ls $dn
Michael Dillon
quelle