Wie kann ich den Namen der Bash-Skriptdatei im Skript selbst ermitteln?
Wenn sich mein Skript in einer Datei befindet runme.sh
, wie würde ich es dann schaffen, die Meldung "Sie führen runme.sh aus" anzuzeigen, ohne dies fest zu codieren?
Wie kann ich den Namen der Bash-Skriptdatei im Skript selbst ermitteln?
Wenn sich mein Skript in einer Datei befindet runme.sh
, wie würde ich es dann schaffen, die Meldung "Sie führen runme.sh aus" anzuzeigen, ohne dies fest zu codieren?
Antworten:
me=`basename "$0"`
Versuchen Sie Folgendes , um einen Symlink 1 zu lesen , der normalerweise nicht Ihren Wünschen entspricht (Sie möchten den Benutzer normalerweise nicht auf diese Weise verwirren):
me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
IMO, das wird verwirrende Ausgabe erzeugen. "Ich habe foo.sh ausgeführt, aber es heißt, ich habe bar.sh ausgeführt!? Muss ein Fehler sein!" Außerdem besteht einer der Zwecke von Symlinks mit unterschiedlichen Namen darin, unterschiedliche Funktionen bereitzustellen, die auf dem Namen basieren, als den sie bezeichnet werden (denken Sie auf einigen Plattformen an gzip und gunzip).
1 Das heißt, um Symlinks so aufzulösen, dass Sie beim Ausführen des Benutzers, foo.sh
der tatsächlich ein Symlink ist bar.sh
, den aufgelösten Namen bar.sh
anstelle von verwenden möchten foo.sh
.
$0
im ersten Beispiel unterliegt die $0
Wortaufteilung, 3. wird an den Basisnamen, den Readlink und das Echo in einer Position übergeben, die es ermöglicht, ihn als Befehlszeilenschalter zu behandeln . Ich schlage stattdessen me=$(basename -- "$0")
oder viel effizienter auf Kosten der Lesbarkeit vor me=${0##*/}
. Für Symlinks, me=$(basename -- "$(readlink -f -- "$0")")
vorausgesetzt gnu utils, wird es sonst ein sehr langes Skript sein, das ich hier nicht schreiben werde.
# ------------- SCRIPT ------------- # # ------------- CALLED ------ ------- #
#!/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
# Beachten Sie, dass in der nächsten Zeile das erste Argument in doppelten # und einfachen Anführungszeichen aufgerufen wird , da es zwei Wörter enthält
$ / misc / shell_scripts / check_root / show_parms . sh "'hallo da'" "'william'"
# ------------- ERGEBNISSE ------------- #
# Argumente aufgerufen mit ---> 'Hallo da' 'William' # $ 1 ----------------------> 'Hallo da' # $ 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 ------------- #
show_params
den Namen ohne optionale Erweiterung?
${0##*/}
. Getestet mit GitBash.
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"
dirname $BASE_SOURCE
" zu verwenden, um das Verzeichnis zu erhalten, in dem sich die Skripte befinden.
$BASH_SOURCE
gibt die richtige Antwort bei der Beschaffung des Skripts.
Dies schließt jedoch den Pfad ein, um nur den Dateinamen des Skripts zu erhalten. Verwenden Sie:
$(basename $BASH_SOURCE)
. <filename> [arguments]
, $0
würden wir den Namen der Anrufer-Shell angeben. Na zumindest unter OSX sicher.
Wenn der Skriptname Leerzeichen enthält, ist es robuster, "$0"
oder "$(basename "$0")"
- oder unter MacOS : "$(basename \"$0\")"
. Dies verhindert, dass der Name in irgendeiner Weise entstellt oder interpretiert wird. Im Allgemeinen empfiehlt es sich, Variablennamen in der Shell immer in doppelte Anführungszeichen zu setzen.
Wenn Sie es ohne den Pfad wollen, würden Sie verwenden ${0##*/}
Um Chris Conway zu antworten , würden Sie (zumindest) unter Linux Folgendes tun:
echo $(basename $(readlink -nf $0))
readlink druckt den Wert eines symbolischen Links aus. Wenn es sich nicht um einen symbolischen Link handelt, wird der Dateiname gedruckt. -n weist es an, keine neue Zeile zu drucken. -f weist ihn 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).
Ich habe festgestellt, dass diese Zeile immer funktioniert, unabhängig davon, ob die Datei bezogen oder als Skript ausgeführt wird.
echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
Wenn Sie Symlinks folgen möchten, verwenden readlink
Sie den oben angegebenen Pfad rekursiv oder nicht rekursiv.
Der Grund, warum der Einzeiler funktioniert, wird durch die Verwendung der BASH_SOURCE
Umgebungsvariablen und ihrer Zuordnung erklärt FUNCNAME
.
BASH_SOURCE
Eine Array-Variable, deren Mitglieder die Quelldateinamen sind, in denen die entsprechenden Shell-Funktionsnamen in der Array-Variablen FUNCNAME 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ührungsaufrufstapel befinden. Das Element mit dem Index 0 ist der Name einer aktuell ausgeführten Shell-Funktion. Das unterste Element (das mit dem höchsten Index) ist "main". Diese Variable existiert nur, wenn eine Shell-Funktion ausgeführt wird. Zuweisungen zu FUNCNAME haben keine Auswirkung und geben einen Fehlerstatus zurück. Wenn FUNCNAME nicht gesetzt ist, verliert es seine besonderen Eigenschaften, auch wenn es anschließend zurückgesetzt wird.
Diese Variable kann mit BASH_LINENO und BASH_SOURCE verwendet werden. Jedes Element von FUNCNAME verfügt über 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]} unter der Zeilennummer $ {BASH_LINENO [$ i]} aufgerufen. Der integrierte Anrufer zeigt anhand dieser Informationen den aktuellen Aufrufstapel an.
[Quelle: Bash-Handbuch]
a
(vorausgesetzt a
, der Inhalt stammt echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
) - dann erhalten Sie a
den Pfad. Aber wenn Sie ein Skript schreiben , b
mit source a
drin und laufen ./b
, es wird zurückkehren b
‚s Weg.
Diese Antworten sind für die angegebenen Fälle korrekt, es besteht jedoch weiterhin ein Problem, wenn Sie das Skript von einem anderen 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. Und in diesem Fall glaube ich nicht, dass es möglich ist, den Namen des Skripts selbst zu erhalten.
Dies ist ein Randfall und sollte nicht zu ernst genommen werden. Wenn Sie das Skript direkt von einem anderen Skript aus ausführen (ohne 'Quelle'), funktioniert die Verwendung von $ 0.
Da einige Kommentare nach dem Dateinamen ohne Erweiterung gefragt haben, ist hier ein Beispiel, wie dies erreicht werden kann:
FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}
Genießen!
Betreff: Tanktalus '(akzeptierte) Antwort oben, ein etwas saubererer Weg ist:
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 bin damit einverstanden, dass es verwirrend wäre, Symlinks zu dereferenzieren, wenn Ihr Ziel darin besteht, dem Benutzer Feedback zu geben, aber es gibt Fälle, in denen Sie den kanonischen Namen für ein Skript oder eine andere Datei benötigen, und dies ist der beste Weg, imo.
source
Skriptnamen.
wenn Ihr Aufruf Shell-Skript wie
/home/mike/runme.sh
$ 0 ist der vollständige Name
/home/mike/runme.sh
Basisname $ 0 erhält den Basisdateinamen
runme.sh
und Sie müssen diesen grundlegenden Namen in eine Variable wie setzen
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"
this="$(dirname "$(realpath "$BASH_SOURCE")")"
Dadurch werden symbolische Links aufgelöst (realpath erledigt das), Leerzeichen werden behandelt (doppelte Anführungszeichen tun dies) und der aktuelle Skriptname wird auch dann gefunden, wenn er von anderen Skripten bezogen (./Myscript) oder aufgerufen wird ($ BASH_SOURCE behandelt dies). Nach all dem ist es gut, dies in einer Umgebungsvariablen zur Wiederverwendung oder zum einfachen Kopieren an eine andere Stelle zu speichern (this =) ...
realpath
Ihrer Information ist kein integrierter BASH-Befehl. Es ist eine eigenständige ausführbare Datei, die nur in bestimmten Distributionen verfügbar ist
In bash
können Sie den Namen der Skriptdatei mit abrufen $0
. Im Allgemeinen $1
, $2
etc. sind für den Zugriff CLI Argumente. Ebenso $0
ist der Zugriff auf den Namen, der das Skript auslöst (Skriptdateiname).
#!/bin/bash
echo "You are running $0"
...
...
Wenn Sie das Skript mit Pfad wie aufrufen /path/to/script.sh
dann $0
auch den Dateinamen geben mit Pfad. In diesem Fall muss $(basename $0)
nur der Name der Skriptdatei verwendet werden.
$0
beantwortet die Frage nicht (so wie ich es verstehe). Eine Demonstration:
$ cat script.sh #! / bin / sh echo `basename $ 0` $ ./script.sh script.sh $ ln script.sh linktoscript $ ./linktoscript Linktoskript
Wie kommt man ./linktoscript
zum Ausdrucken script.sh
?
[EDIT] Per @ephemient in den obigen Kommentaren, obwohl die symbolische Verknüpfung erfunden zu sein scheint, ist es möglich, damit herumzuspielen $0
, dass sie keine Dateisystemressource darstellt. Das OP ist etwas mehrdeutig in Bezug auf das, was er wollte.
Info danke an Bill Hernandez. Ich habe einige Einstellungen 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
Kurz, klar und einfach 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.
DIRECTORY=$(cd `dirname $0` && pwd)
Ich habe das Obige aus einer anderen Frage zum Stapelüberlauf erhalten. Kann ein Bash-Skript feststellen, in welchem Verzeichnis es gespeichert ist? , aber ich denke, es ist auch für dieses Thema nützlich.
Folgendes habe ich mir ausgedacht, inspiriert von Dimitre Radoulovs Antwort (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
so etwas?
export LC_ALL=en_US.UTF-8
#!/bin/bash
#!/bin/sh
#----------------------------------------------------------------------
start_trash(){
ver="htrash.sh v0.0.4"
$TRASH_DIR # url to trash $MY_USER
$TRASH_SIZE # Show Trash Folder Size
echo "Would you like to empty Trash [y/n]?"
read ans
if [ $ans = y -o $ans = Y -o $ans = yes -o $ans = Yes -o $ans = YES ]
then
echo "'yes'"
cd $TRASH_DIR && $EMPTY_TRASH
fi
if [ $ans = n -o $ans = N -o $ans = no -o $ans = No -o $ans = NO ]
then
echo "'no'"
fi
return $TRUE
}
#-----------------------------------------------------------------------
start_help(){
echo "HELP COMMANDS-----------------------------"
echo "htest www open a homepage "
echo "htest trash empty trash "
return $TRUE
} #end Help
#-----------------------------------------------#
homepage=""
return $TRUE
} #end cpdebtemp
# -Case start
# if no command line arg given
# set val to Unknown
if [ -z $1 ]
then
val="*** Unknown ***"
elif [ -n $1 ]
then
# otherwise make first arg as val
val=$1
fi
# use case statement to make decision for rental
case $val in
"trash") start_trash ;;
"help") start_help ;;
"www") firefox $homepage ;;
*) echo "Sorry, I can not get a $val for you!";;
esac
# Case stop