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?
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).
# ------------- 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 ------------- #
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"
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.
$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)
Si vous le voulez sans le chemin, vous utiliseriez ${0##*/}
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).
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]
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.
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.
Certains commentaires demandant le nom de fichier sans extension, voici un exemple comment procéder:
FileName=${0##*/}
FileNameWithoutExtension=${FileName%.*}
Prendre plaisir!
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"
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 =) ...
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
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.
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é
echo "$(basename "`test -L ${BASH_SOURCE[0]} \
&& readlink ${BASH_SOURCE[0]} \
|| echo ${BASH_SOURCE[0]}`")"
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
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.
echo "Vous utilisez $ 0"
$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.
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.