265 votes

Comment détecter si un script est recherché

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é?

199voto

barroyo Points 241

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 ..."
 

84voto

Dennis Williamson Points 105818

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).

79voto

F. Hauri Points 5893

Après la lecture de @DennisWilliamson réponse, il y a quelques isues, voir ci-dessous.

Comme cette question stand pour et , il ya une autre partie de cette réponse concernant le ... voir ci-dessous.

Simple 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: maintenant...

Comme je n'utilise pas 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 .

33voto

mr.spuratic Points 2205

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.

3voto

user354193 Points 53

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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X