web-dev-qa-db-de.com

Wie erfahre ich den Namen der Skriptdatei in einem Bash-Skript?

Wie kann ich den Namen der Bash-Skriptdatei im Skript selbst ermitteln?

Wenn sich mein Skript in der Datei runme.sh befindet, wie kann ich dann die Meldung "Sie führen runme.sh" anzeigen, ohne dass dies festgeschrieben wird?

490
Ma99uS
me=`basename "$0"`

Um einen Symlink zu lesen, der normalerweise nicht das ist, was Sie möchten (Sie möchten den Benutzer normalerweise nicht auf diese Weise verwirren), versuchen Sie Folgendes:

me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"

IMO, das wird zu verwirrenden Ergebnissen führen. "Ich bin foo.sh gelaufen, aber es heißt, dass ich bar.sh betreibe !? Muss ein Fehler sein!" Außerdem besteht der Zweck von Symlinks mit unterschiedlichen Namen darin, unterschiedliche Funktionen bereitzustellen, die auf dem Namen basieren, den sie als bezeichnet haben (denken Sie auf einigen Plattformen an gzip und gunzip).

518
Tanktalus
 # ------------- SCRIPT ------------- # 

#!/bin/bash

echo
echo "# arguments called with ---->  ${@}     "
echo "# \$1 ---------------------->  $1       "
echo "# \$2 ---------------------->  $2       "
echo "# path to me --------------->  ${0}     "
echo "# parent path -------------->  ${0%/*}  "
echo "# my name ------------------>  ${0##*/} "
echo
exit

 # ---------- --- CALLED ------------- # 

 # Beachten Sie, dass in der nächsten Zeile das erste Argument innerhalb von double, 
 # Und einfachen Anführungszeichen aufgerufen wird, da es enthält zwei Wörter 

 $ /misc/Shell_scripts/check_root/show_parms.sh "" Hallo dort "" "" "william" "

 # --------- ---- ERGEBNISSE ------------- # 

 # Argumente aufgerufen mit ---> 'Hallo dort' 'william' 
 # $ 1 ----- -----------------> "Hallo dort" 
 # $ 2 ----------------------> 'william' 
 # pfad zu mir --------------> /misc/Shell_scripts/check_root/show_parms.sh
# übergeordneter Pfad --------- ----> /misc/Shell_scripts/check_root
# mein name -----------------> show_parms.sh 

 # ----- -------- ENDE ------------- #
212
Bill Hernandez

Mit bash> = 3 funktioniert folgendes:

$ ./s
0 is: ./s
BASH_SOURCE is: ./s
$ . ./s
0 is: bash
BASH_SOURCE is: ./s

$ cat s
#!/bin/bash

printf '$0 is: %s\n$BASH_SOURCE is: %s\n' "$0" "$BASH_SOURCE"
172

Wenn der Skriptname Leerzeichen enthält, verwenden Sie "$0" oder "$(basename "$0")" - oder unter MacOS "$(basename \"$0\")" eine robustere Methode. Dies verhindert, dass der Name in irgendeiner Weise verstümmelt oder interpretiert wird. Im Allgemeinen empfiehlt es sich, Variablennamen in der Shell immer in doppelte Anführungszeichen zu setzen.

60
Josh Lee

$BASH_SOURCE gibt die richtige Antwort, wenn Sie das Skript beziehen.

Dies beinhaltet jedoch den Pfad, um nur den Dateinamen der Skripts zu erhalten:

$(basename $BASH_SOURCE) 
58
Zainka

Wenn Sie es ohne Pfad wünschen, würden Sie ${0##*/} verwenden.

21
Mr. Muskrat

Um Chris Conway zu beantworten, würden Sie zumindest unter Linux Folgendes tun:

echo $(basename $(readlink -nf $0))

readlink gibt den Wert eines symbolischen Links aus. Wenn es sich nicht um einen symbolischen Link handelt, wird der Dateiname ausgegeben. -n teilt mit, dass keine Zeilenumbrüche gedruckt werden sollen. -f weist den Link an, dem Link vollständig zu folgen (wenn ein symbolischer Link ein Link zu einem anderen Link wäre, würde dieser ebenfalls aufgelöst).

19

Ich habe festgestellt, dass diese Zeile immer funktioniert, unabhängig davon, ob die Datei beschafft oder als Skript ausgeführt wird.

echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"

Wenn Sie Symlinks folgen möchten, verwenden Sie readlink für den Pfad, den Sie oben angegeben haben, rekursiv oder nichtrekursiv.

Der Grund, warum der Einzeiler funktioniert, wird durch die Verwendung der Umgebungsvariable BASH_SOURCE und der zugehörigen Variable FUNCNAME erklärt.

BASH_SOURCE

Eine Array-Variable, deren Mitglieder die Quelldateinamen sind, in denen die entsprechenden Shell-Funktionsnamen in der FUNCNAME-Array-Variablen definiert sind. Die Shell-Funktion $ {FUNCNAME [$ i]} ist in der Datei $ {BASH_SOURCE [$ i]} definiert und wird von $ {BASH_SOURCE [$ i + 1]} aufgerufen.

FUNCNAME

Eine Array-Variable, die die Namen aller Shell-Funktionen enthält, die sich derzeit im Ausführungsaufruf-Stack befinden Das Element mit dem Index 0 ist der Name einer aktuell ausgeführten Shell-Funktion. Das unterste Element (das Element mit dem höchsten Index) ist "main". Diese Variable ist nur vorhanden, wenn eine Shell-Funktion ausgeführt wird. Zuweisungen an FUNCNAME haben keine Auswirkungen und geben einen Fehlerstatus zurück. Wenn FUNCNAME nicht gesetzt ist, verliert es seine speziellen Eigenschaften, auch wenn es später zurückgesetzt wird. 

Diese Variable kann mit BASH_LINENO und BASH_SOURCE verwendet werden. Jedes Element von FUNCNAME enthält entsprechende Elemente in BASH_LINENO und BASH_SOURCE, um den Aufrufstapel zu beschreiben. Zum Beispiel wurde $ {FUNCNAME [$ i]} aus der Datei $ {BASH_SOURCE [$ i + 1]} in Zeilennummer $ {BASH_LINENO [$ i]} aufgerufen. Der eingebaute Anrufer zeigt den aktuellen Anrufstapel anhand dieser Informationen an.

[Quelle: Bash-Handbuch]

13
gkb0986

Diese Antworten sind für die angegebenen Fälle korrekt. Es gibt jedoch immer noch ein Problem, wenn Sie das Skript über ein anderes Skript mit dem Schlüsselwort 'source' ausführen (sodass es in derselben Shell ausgeführt wird). In diesem Fall erhalten Sie die $ 0 des aufrufenden Skripts. In diesem Fall glaube ich nicht, dass es möglich ist, den Namen des Skripts selbst zu ermitteln.

Dies ist ein Edge-Fall und sollte nicht zu ernst genommen werden. Wenn Sie das Skript direkt aus einem anderen Skript (ohne 'source') ausführen, funktioniert die Verwendung von $ 0.

11
Jim Dodd

Re: Tanktalus (akzeptierte) Antwort oben, eine etwas sauberere Methode ist die Verwendung von:

me=$(readlink --canonicalize --no-newline $0)

Wenn Ihr Skript aus einem anderen Bash-Skript stammt, können Sie Folgendes verwenden:

me=$(readlink --canonicalize --no-newline $BASH_SOURCE)

Ich stimme zu, dass es verwirrend sein könnte, Symlinks zu dereferenzieren, wenn Ihr Ziel darin besteht, dem Benutzer Feedback zu geben. In manchen Fällen müssen Sie jedoch den kanonischen Namen eines Skripts oder einer anderen Datei erhalten.

8
simon

Da in einigen Kommentaren nach dem Dateinamen ohne Erweiterung gefragt wurde, folgt hier ein Beispiel, wie das zu erreichen ist:

FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}

Genießen!

7
Simon Mattes

wenn Sie ein Shell-Skript aufrufen möchten 

/home/mike/runme.sh

$ 0 ist vollständiger Name

 /home/mike/runme.sh

basisname $ 0 erhält den Namen der Basisdatei

 runme.sh

und Sie müssen diesen grundlegenden Namen in eine Variable wie einfügen

filename=$(basename $0)

und fügen Sie Ihren zusätzlichen Text hinzu 

echo "You are running $filename"

so mögen deine Skripte 

/home/mike/runme.sh
#!/bin/bash 
filename=$(basename $0)
echo "You are running $filename"
6
LawrenceLi
this="$(dirname "$(realpath "$BASH_SOURCE")")"

Dies löst symbolische Links auf (realpath macht das), behandelt Leerzeichen (doppelte Anführungszeichen) und findet den aktuellen Skriptnamen auch dann, wenn er (. ./Myscript) oder von anderen Skripten aufgerufen wird ($ BASH_SOURCE behandelt das). Nach all dem ist es gut, dies in einer Umgebungsvariablen für die Wiederverwendung oder zum einfachen Kopieren an anderer Stelle (this =) zu speichern.

5
jcalfee314

Sie können $ 0 verwenden, um Ihren Skriptnamen (mit vollständigem Pfad) zu ermitteln. Um nur den Skriptnamen zu erhalten, können Sie diese Variable mit trimmen

basename $0
5
VolkA

In bash können Sie den Namen der Skriptdatei mit $0 abrufen. Im Allgemeinen sind $1, $2 etc für den Zugriff auf CLI-Argumente bestimmt. Ebenso soll $0 auf den Namen zugreifen, der das Skript auslöst (Skriptdateiname).

#!/bin/bash
echo "You are running $0"
...
...

Wenn Sie das Skript mit dem Pfad /path/to/script.sh aufrufen, gibt $0 auch den Dateinamen mit dem Pfad an. In diesem Fall müssen Sie $(basename $0) verwenden, um nur den Namen der Skriptdatei zu erhalten.

2
rashok

Info danke an Bill Hernandez. Ich habe einige Präferenzen hinzugefügt, die ich übernehme.

#!/bin/bash
function Usage(){
    echo " Usage: show_parameters [ arg1 ][ arg2 ]"
}
[[ ${#2} -eq 0 ]] && Usage || {
    echo
    echo "# arguments called with ---->  ${@}     "
    echo "# \$1 ----------------------->  $1       "
    echo "# \$2 ----------------------->  $2       "
    echo "# path to me --------------->  ${0}     " | sed "s/$USER/\$USER/g"
    echo "# parent path -------------->  ${0%/*}  " | sed "s/$USER/\$USER/g"
    echo "# my name ------------------>  ${0##*/} "
    echo
}

Prost

2
linxuser
echo "$(basename "`test -L ${BASH_SOURCE[0]} \
                   && readlink ${BASH_SOURCE[0]} \
                   || echo ${BASH_SOURCE[0]}`")"
1
ecwpz91

Folgendes habe ich mir ausgedacht, inspiriert von der Antwort von Dimitre Radoulov (die ich übrigens positiv bewertet habe) .

script="$BASH_SOURCE"
[ -z "$BASH_SOURCE" ] && script="$0"

echo "Called $script with $# argument(s)"

unabhängig davon, wie Sie Ihr Skript aufrufen

. path/to/script.sh

oder

./path/to/script.sh
0

Kurz, klar und einfach in my_script.sh

#!/bin/bash

running_file_name=$(basename "$0")

echo "You are running '$running_file_name' file."

Ausgabe:

./my_script.sh
You are running 'my_script.sh' file.
0

echo "Sie laufen $ 0"

0
mmacaulay

$0 beantwortet die Frage nicht (so wie ich sie verstehe). Eine Demonstration:

 $ cat script.sh 
 #! /bin/sh
echo `Basisname $ 0` 
 $ ./script.sh 
 script.sh 
 $ ln script.sh-Linktoskript 
 $ ./linktoscript 
 linktoscript 

Wie bekommt man ./linktoscript, um script.sh auszudrucken?

[EDIT] Per @ephemient in den obigen Kommentaren. Obwohl die symbolische Verknüpfung etwas durchdacht erscheinen mag, ist es möglich, mit $0 so zu arbeiten, dass sie keine Dateisystemressource darstellt. Das OP ist etwas unklar, was er wollte.

0
Chris Conway
DIRECTORY=$(cd `dirname $0` && pwd)

Ich habe das obige von einer anderen Stack Overflow-Frage erhalten, Kann ein Bash-Skript herausfinden, in welchem ​​Verzeichnis es gespeichert ist?, aber ich denke, es ist auch für dieses Thema nützlich.

0
Koter84