web-dev-qa-db-fra.com

Comment connaître le nom du fichier de script dans un script Bash?

Comment puis-je déterminer le nom du fichier de script Bash dans le script lui-même?

Comme si mon script est dans le fichier runme.sh, comment puis-je le faire pour afficher le message "Vous exécutez runme.sh" sans le coder en dur?

490
Ma99uS
me=`basename "$0"`

Pour lire un lien symbolique, ce qui n’est généralement pas ce que vous voulez (vous ne voulez généralement pas dérouter l’utilisateur de cette façon), essayez:

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

OMI, ça va produire une sortie déroutante. "J'ai couru foo.sh, mais ça veut dire que je cours bar.sh !? Doit être un bug!" En outre, l'un des objectifs des liens symboliques nommés différemment est de fournir différentes fonctionnalités en fonction du nom appelé (pensez à gzip et gunzip sur certaines plates-formes).

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 ------------- # 

 # Sur la ligne suivante, le premier argument est appelé entre guillemets doubles, 
 # Et simples, car il contient deux mots 

 $ /misc/Shell_scripts/check_root/show_parms.sh "'bonjour' '' '' william '" 

 # --------- ---- RÉSULTATS ------------- # 

 # Arguments appelés avec ---> 'bonjour' 'william' 
 # $ 1 ----- -----------------> 'bonjour là-bas' 
 # $ 2 ----------------------> 'william' 
 # chemin d'accès --------------> /misc/Shell_scripts/check_root/show_parms.sh
# chemin d'accès parent --------- ----> /misc/Shell_scripts/check_root
# mon nom -----------------> show_parms.sh 

 # ----- -------- FIN ------------- #
212
Bill Hernandez

Avec bash> = 3 les travaux suivants:

$ ./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
Dimitre Radoulov

Si le nom du script contient des espaces, une méthode plus robuste consiste à utiliser "$0" ou "$(basename "$0")" - ou sur MacOS: "$(basename \"$0\")". Cela empêche le nom d'être mutilé ou interprété de quelque manière que ce soit. En règle générale, il est recommandé de toujours mettre les noms de variables entre guillemets dans le shell.

60
Josh Lee

$BASH_SOURCE donne la réponse correcte lors de la recherche du script.

Cependant, cela inclut le chemin, donc pour obtenir le nom de fichier des scripts, utilisez:

$(basename $BASH_SOURCE) 
58
Zainka

Si vous le voulez sans le chemin, vous utiliseriez ${0##*/}

21
Mr. Muskrat

Pour répondre à Chris Conway , sous Linux (au moins), vous feriez ceci:

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

readlink affiche la valeur d'un lien symbolique. S'il ne s'agit pas d'un lien symbolique, le nom du fichier est imprimé. -n lui dit de ne pas imprimer de saut de ligne. -f lui dit de suivre le lien complètement (si un lien symbolique était un lien vers un autre lien, il le résoudrait également).

19
Travis B. Hartwell

J'ai trouvé que cette ligne fonctionnait toujours, que le fichier soit recherché ou exécuté en tant que script.

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

Si vous souhaitez suivre les liens symboliques, utilisez readlink sur le chemin que vous obtenez ci-dessus, de manière récursive ou non récursive.

La raison pour laquelle one-liner fonctionne est expliquée par l'utilisation de la variable d'environnement BASH_SOURCE et de son associé FUNCNAME.

BASH_SOURCE

Une variable de tableau dont les membres sont les noms de fichiers source, où les noms de fonction Shell correspondants dans la variable de tableau FUNCNAME sont définis. La fonction shell $ {FUNCNAME [$ i]} est définie dans le fichier $ {BASH_SOURCE [$ i]} et appelée à partir de $ {BASH_SOURCE [$ i + 1]}.

FUNCNAME

Une variable de tableau contenant les noms de toutes les fonctions du shell actuellement dans la pile d'appels d'exécution. L'élément d'indice 0 est le nom de toute fonction Shell en cours d'exécution. L'élément le plus bas (celui avec l'indice le plus élevé) est "principal". Cette variable n'existe que lorsqu'une fonction Shell est en cours d'exécution. Les assignations à FUNCNAME n'ont aucun effet et renvoient un statut d'erreur. Si FUNCNAME n'est pas défini, il perd ses propriétés spéciales, même s'il est réinitialisé ultérieurement. 

Cette variable peut être utilisée avec BASH_LINENO et BASH_SOURCE. Chaque élément de FUNCNAME a des éléments correspondants dans BASH_LINENO et BASH_SOURCE pour décrire la pile d'appels. Par exemple, $ {FUNCNAME [$ i]} a été appelé à partir du fichier $ {BASH_SOURCE [$ i + 1]} au numéro de ligne $ {BASH_LINENO [$ i]}. L'appelant intégré affiche la pile d'appels en cours en utilisant ces informations.

[Source: Manuel Bash]

13
gkb0986

Ces réponses sont correctes pour les cas qu'elles indiquent, mais le problème persiste si vous exécutez le script à partir d'un autre script à l'aide du mot clé "source" (afin qu'il soit exécuté dans le même shell). Dans ce cas, vous obtenez le $ 0 du script d'appel. Et dans ce cas, je ne pense pas qu'il soit possible d'obtenir le nom du script lui-même.

Ceci est un cas Edge et ne doit pas être pris trop au sérieux. Si vous exécutez le script à partir d'un autre script directement (sans 'source'), utiliser $ 0 fonctionnera.

11
Jim Dodd

Réponse de Tanktalus (acceptée) ci-dessus, une manière légèrement plus propre consiste à utiliser:

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

Si votre script provient d'un autre script bash, vous pouvez utiliser:

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

Je conviens qu’il serait déroutant de déréférencer les liens symboliques si votre objectif est de fournir des commentaires à l’utilisateur, mais vous avez parfois besoin d’obtenir le nom canonique dans un script ou un autre fichier, et c’est le meilleur moyen, imo.

8
simon

Certains commentaires demandant le nom de fichier sans extension, voici un exemple comment procéder:

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

Prendre plaisir!

7
Simon Mattes

si votre script d'invocation Shell ressemble à 

/home/mike/runme.sh

$ 0 est le nom complet

 /home/mike/runme.sh

nom_base $ 0 recevra le nom du fichier de base

 runme.sh

et vous devez mettre ce nom de base dans une variable comme

filename=$(basename $0)

et ajoutez votre texte supplémentaire 

echo "You are running $filename"

donc vos scripts aiment 

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

Cela résout les liens symboliques (realpath le fait), gère les espaces (les guillemets doubles) et trouve le nom du script actuel même lorsqu'il est généré (. ./Myscript) ou appelé par d'autres scripts ($ BASH_SOURCE le gère). Après tout, il est bon de sauvegarder cela dans une variable d’environnement pour pouvoir le réutiliser ou pour le copier facilement ailleurs (this =) ...

5
jcalfee314

Vous pouvez utiliser $ 0 pour déterminer votre nom de script (avec chemin complet). Pour obtenir le nom de script uniquement, vous pouvez ajuster cette variable avec

basename $0
5
VolkA

Dans bash, vous pouvez obtenir le nom du fichier de script à l'aide de $0. Généralement, $1, $2, etc. permettent d’accéder aux arguments de la CLI. De même, $0 permet d’accéder au nom qui déclenche le script (nom du fichier de script).

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

Si vous appelez le script avec un chemin tel que /path/to/script.sh, alors $0 donnera également le nom de fichier avec chemin. Dans ce cas, vous devez utiliser $(basename $0) pour obtenir uniquement le nom du fichier de script.

2
rashok

Info grâce à Bill Hernandez. J'ai ajouté quelques préférences que je suis en train d'adopter.

#!/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
}

À votre santé

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

Voici ce que j’ai trouvé, inspiré par la réponse de Dimitre Radoulov(que j’ai voté au passage).

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

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

peu importe comment vous appelez votre script

. path/to/script.sh

ou

./path/to/script.sh
0
Salathiel Genèse

Bref, clair et simple, en my_script.sh

#!/bin/bash

running_file_name=$(basename "$0")

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

Out mis:

./my_script.sh
You are running 'my_script.sh' file.
0
Bơ Loong A Nhứi

echo "Vous utilisez $ 0"

0
mmacaulay

$0 ne répond pas à la question (si je comprends bien). Une démonstration:

 $ cat script.sh 
 #! /bin/sh
echo `basename $ 0` 
 $ ./script.sh 
 script.sh 
 $ ln Dans script.sh linktoscript 
 $ ./linktoscript 
 linktoscript 

Comment peut-on obtenir ./linktoscript pour imprimer script.sh?

[EDIT] Par @ ephemient dans les commentaires ci-dessus, bien que le lien symbolique puisse sembler artificiel, il est possible de jouer avec $0 de telle sorte qu'il ne représente pas une ressource de système de fichiers. Le PO est un peu ambigu sur ce qu'il voulait.

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

J'ai eu ce qui précède d'une autre question de débordement de pile, Un script Bash peut-il indiquer dans quel répertoire il est stocké?, mais je pense que c'est utile pour ce sujet également.

0
Koter84