J'ai un script où je ne veux pas qu'il appelle "exit" s'il est recherché. Initialement, je me suis demandé si vérifier si $0 == bash
mais cela pose des problèmes si le script provient d’un autre script ou si l’utilisateur le source à partir de ksh. Existe-t-il un moyen fiable de détecter si un script est recherché?
Réponses
Trop de publicités?Si votre version de Bash est au courant de la variable de tableau BASH_SOURCE, essayez l'une des solutions suivantes:
# man bash | less -p BASH_SOURCE
#[[ ${BASH_VERSINFO[0]} -le 2 ]] && echo 'No BASH_SOURCE array variable' && exit 1
[[ "${BASH_SOURCE[0]}" != "${0}" ]] && echo "script ${BASH_SOURCE[0]} is being sourced ..."
Cela semble être portable entre Bash et Korn:
[[ $_ != $0 ]] && echo "Script is being sourced" || echo "Script is a subshell"
Une ligne similaire à celle-ci ou une affectation telle que `pathname =" $ _ "(avec un test et une action ultérieurs) doit figurer sur la première ligne du script ou sur la ligne après le shebang (qui, si elle est utilisée, devrait être pour ksh pour que cela fonctionne dans la plupart des circonstances).
Après la lecture de @DennisWilliamson réponse, il y a quelques isues, voir ci-dessous.
Comme cette question stand pour ksh et bash, il ya une autre partie de cette réponse concernant le ksh... voir ci-dessous.
Simple bash façon
[ "$0" = "$BASH_SOURCE" ]
Nous allons essayer (à la volée parce que bash ;-):
source <(echo $'#!/bin/bash
[ "$0" = "$BASH_SOURCE" ] && v=own || v=sourced;
echo "process $$ is $v ($0, $BASH_SOURCE)" ')
process 29301 is sourced (bash, /dev/fd/63)
bash <(echo $'#!/bin/bash
[ "$0" = "$BASH_SOURCE" ] && v=own || v=sourced;
echo "process $$ is $v ($0, $BASH_SOURCE)" ')
process 16229 is own (/dev/fd/63, /dev/fd/63)
J'utilise source
au lieu d' .
pour des raisons de lisibilité ( .
est un alias source
):
. <(echo $'#!/bin/bash
[ "$0" = "$BASH_SOURCE" ] && v=own || v=sourced;
echo "process $$ is $v ($0, $BASH_SOURCE)" ')
process 29301 is sourced (bash, /dev/fd/63)
Notez que le numéro de processus ne change pas alors que le processus de séjour source:
echo $$
29301
Pourquoi ne pas utiliser $_ == $0
comparission
Pour assurer de nombreux cas, je commence à écrire un vrai script:
#!/bin/bash
# As $_ could be used only once, uncomment one of two following lines
#printf '_="%s", 0="%s" and BASH_SOURCE="%s"\n' "$_" "$0" "$BASH_SOURCE"
[[ "$_" != "$0" ]] && DW_PURPOSE=sourced || DW_PURPOSE=subshell
[ "$0" = "$BASH_SOURCE" ] && BASH_KIND_ENV=own || BASH_KIND_ENV=sourced;
echo "proc: $$[ppid:$PPID] is $BASH_KIND_ENV (DW purpose: $DW_PURPOSE)"
Le copier dans un fichier appelé testscript
:
cat >testscript
chmod +x testscript
Maintenant, nous avons pu tester:
./testscript
proc: 25758[ppid:24890] is own (DW purpose: subshell)
C'est ok.
. ./testscript
proc: 24890[ppid:24885] is sourced (DW purpose: sourced)
source ./testscript
proc: 24890[ppid:24885] is sourced (DW purpose: sourced)
C'est ok.
Mais,pour le test d'un script avant de l'ajouter -x
drapeau:
bash ./testscript
proc: 25776[ppid:24890] is own (DW purpose: sourced)
Ou d'utiliser des variables prédéfinies:
env PATH=/tmp/bintemp:$PATH ./testscript
proc: 25948[ppid:24890] is own (DW purpose: sourced)
env SOMETHING=PREDEFINED ./testscript
proc: 25972[ppid:24890] is own (DW purpose: sourced)
Cela ne fonctionne plus.
Le déplacement de commentaires à partir de la 5ème ligne pour les classes de 6ème, permettrait de donner plus lisible réponse:
./testscript
_="./testscript", 0="./testscript" and BASH_SOURCE="./testscript"
proc: 26256[ppid:24890] is own
. testscript
_="_filedir", 0="bash" and BASH_SOURCE="testscript"
proc: 24890[ppid:24885] is sourced
source testscript
_="_filedir", 0="bash" and BASH_SOURCE="testscript"
proc: 24890[ppid:24885] is sourced
bash testscript
_="/bin/bash", 0="testscript" and BASH_SOURCE="testscript"
proc: 26317[ppid:24890] is own
env FILE=/dev/null ./testscript
_="/usr/bin/env", 0="./testscript" and BASH_SOURCE="./testscript"
proc: 26336[ppid:24890] is own
Plus difficile: ksh maintenant...
Comme je n'utilise pas ksh beaucoup, après quelques lire sur la page de man, il y a ma tente:
#!/bin/ksh
set >/tmp/ksh-$$.log
Copiez ceci dans un testfile.ksh
:
cat >testfile.ksh
chmod +x testfile.ksh
Que de l'exécuter en deux temps:
./testfile.ksh
. ./testfile.ksh
ls -l /tmp/ksh-*.log
-rw-r--r-- 1 user user 2183 avr 11 13:48 /tmp/ksh-9725.log
-rw-r--r-- 1 user user 2140 avr 11 13:48 /tmp/ksh-9781.log
echo $$
9725
et à voir:
diff /tmp/ksh-{9725,9781}.log | grep ^\> # OWN SUBSHELL:
> HISTCMD=0
> PPID=9725
> RANDOM=1626
> SECONDS=0.001
> lineno=0
> SHLVL=3
diff /tmp/ksh-{9725,9781}.log | grep ^\< # SOURCED:
< COLUMNS=152
< HISTCMD=117
< LINES=47
< PPID=9163
< PS1='$ '
< RANDOM=29667
< SECONDS=23.652
< level=1
< lineno=1
< SHLVL=2
Il y a certaines variables herited dans une source exécuter, mais rien de vraiment...
Vous pouvez même vérifier qu' $SECONDS
est proche de 0.000
, mais c'est de s'assurer uniquement à la main provenant de cas...
Vous pourriez essayer de vérifier ce qui est des parents est:
Placez ceci dans votre testfile.ksh
:
ps $PPID
Que:
./testfile.ksh
PID TTY STAT TIME COMMAND
32320 pts/4 Ss 0:00 -ksh
. ./testfile.ksh
PID TTY STAT TIME COMMAND
32319 ? S 0:00 sshd: user@pts/4
ou ps ho cmd $PPID
, mais ce travail qu'à un niveau de subsessions...
Désolé, je ne pouvais pas trouver un moyen fiable de le faire, en vertu de ksh.
L' BASH_SOURCE[]
de réponses (bash-3.0 et versions ultérieures) semble plus simple, mais BASH_SOURCE[]
est pas documentée à travailler à l'extérieur du corps d'une fonction (actuellement il arrive à travailler, en désaccord avec la page de man).
Le plus robuste, comme suggéré par Wirawan Purwanto, est de vérifier FUNCNAME[1]
au sein d'une fonction:
function mycheck() { declare -p FUNCNAME; }
mycheck
Alors:
$ bash sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="main")'
$ . sourcetest.sh
declare -a FUNCNAME='([0]="mycheck" [1]="source")'
C'est l'équivalent de la vérification de la sortie de l' caller 1
, les valeurs main
et source
de la distinguer de l'appelant au contexte. À l'aide de FUNCNAME[]
vous permet d'économiser de l'analyse syntaxique caller
de la production. Vous avez besoin de connaître votre appel local profondeur correcte. Des cas pathologiques, comme un script provenant de l'intérieur d'une autre fonction ou un script sera la cause de la matrice (pile) pour être plus profond.
Cependant, le problème le plus indiqué est "j'ai un script où je ne veux pas qu'il appel "quitter" si il est de source". La commune bash
idiome de cette situation est la suivante:
return 2>/dev/null || exit
Si le script est en cours provenant ensuite, return
mettra fin à la source du script et de retour à l'appelant.
Si le script est exécuté, alors return
retournera un message d'erreur (redirigé), et exit
va se terminer le script comme d'habitude. Les deux return
et exit
pouvez prendre un code de sortie, si nécessaire.
Malheureusement, cela ne fonctionne pas, en ksh
(au moins pas dans l'AT&T version d'origine que j'ai ici), il traite l' return
comme équivalent à exit
lorsqu'elle est invoquée à l'extérieur d'une fonction ou le point d'origine de script.
La réponse canonique ici: http://mywiki.wooledge.org/BashFAQ/109 propose également $-
comme un autre indicateur (bien qu'imparfaite) de la coquille de l'état.
J'aimerais suggérer une petite correction à la réponse très utile de Dennis, pour la rendre légèrement plus portable, j'espère:
[ "$_" != "$0" ] && echo "Script is being sourced" || echo "Script is a subshell"
parce que [[n’est pas reconnu par le shell (compatible POSIX 'de Debian,' dash '(Debian). En outre, vous pouvez avoir besoin des guillemets pour vous protéger des noms de fichiers contenant des espaces, également dans ledit shell.