J'ai un script où je ne veux pas qu'il appelle exit
s'il provient.
J'ai pensé à vérifier si $0 == bash
cela avait des problèmes si le script provient d'un autre script, ou si l'utilisateur le source à partir d'un autre shell comme ksh
.
Existe-t-il un moyen fiable de détecter si un script provient?
Réponses:
Cela semble être portable entre Bash et Korn:
Une ligne similaire à celle-ci ou une affectation comme
pathname="$_"
(avec un test et une action ultérieurs) doit être 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 qu'elle fonctionne sous la plupart des circonstances).la source
BASH_ENV
,$_
en haut du script sera la dernière commande exécutée à partir deBASH_ENV
.$_
est un problème.bash script
(invocation via un exécutable shell, que cette solution dénature comme source ), et (b) (beaucoup moins probable)echo bash; . script
(si$_
cela correspond au shell qui approvisionne le script, cette solution le dénature comme un sous - shell ). Seules les variables spéciales spécifiques au shell (par exemple,$BASH_SOURCE
) permettent des solutions robustes (il s'ensuit qu'il n'y a pas de solution robuste compatible POSIX). Il est possible, quoique lourd, de concevoir un test croisé robuste.Si votre version Bash connaît la variable de tableau BASH_SOURCE, essayez quelque chose comme:
la source
${BASH_SOURCE[0]}
au lieu de juste$BASH_SOURCE
? Et${0}
vs$0
?BASH_SOURCE
est une variable de tableau (voir manuel ) qui contient une trace de pile des sources, où${BASH_SOURCE[0]}
est la dernière. Les accolades sont utilisées ici pour indiquer au bash ce qui fait partie du nom de la variable. Ils ne sont pas nécessaires$0
dans ce cas, mais ils ne font pas de mal non plus. ;)$array
, vous obtenez${array[0]}
par défaut. Alors, encore une fois, y a-t-il une raison [...]?Solutions solides pour
bash
,ksh
,zsh
, comprenant une contre-coquille une, plus une assez robuste solution compatible POSIX :Les numéros de version sont données celles sur lesquelles la fonctionnalité a été vérifiée - probablement, ces solutions fonctionnent sur des versions beaucoup plus tôt, trop - bienvenue de retour .
En utilisant uniquement les fonctionnalités POSIX (comme dans
dash
, qui agit comme/bin/sh
sur Ubuntu), il n'existe aucun moyen robuste de déterminer si un script est en cours de sourcing - voir ci-dessous pour la meilleure approximation .Les lignes simples suivent - explication ci-dessous; la version cross-shell est complexe, mais elle devrait fonctionner de manière robuste:
bash (vérifié les 3.57 et 4.4.19)
ksh (vérifié sur 93u +)
zsh (vérifié sur 5.0.5) - assurez-vous d'appeler cela en dehors d'une fonction
cross-shell (bash, ksh, zsh)
Conforme POSIX ; pas un seul liner (pipeline unique) pour des raisons techniques et pas entièrement robuste (voir en bas):
Explication:
frapper
Remarque: La technique a été adaptée de la réponse de user5754163 , car elle s'est avérée être plus robuste que la solution d'origine,
[[ $0 != "$BASH_SOURCE" ]] && sourced=1 || sourced=0
[1]Bash autorise les
return
instructions uniquement à partir des fonctions et, dans la portée de niveau supérieur d'un script, uniquement si le script provient .return
est utilisé dans la portée de niveau supérieur d'un script non source , un message d'erreur est émis et le code de sortie est défini sur1
.(return 0 2>/dev/null)
s'exécutereturn
dans un sous - shell et supprime le message d'erreur; ensuite, le code de sortie indique si le script a été généré (0
) ou non (1
), qui est utilisé avec les opérateurs&&
et||
pour définir lasourced
variable en conséquence.return
dans la portée de niveau supérieur d'un script source quitterait le script.0
commereturn
opérande; il note: par bash aide dereturn [N]
: "Si N est omis, le statut de retour est celui de la dernière commande." Par conséquent, la version antérieure [qui utilisait justereturn
, sans opérande] produit un résultat incorrect si la dernière commande sur le shell de l'utilisateur a une valeur de retour non nulle.ksh
La variable spéciale
${.sh.file}
est quelque peu analogue à$BASH_SOURCE
; notez que cela${.sh.file}
provoque une erreur de syntaxe dans bash, zsh et dash, alors assurez-vous de l'exécuter conditionnellement dans des scripts multi-shell.Contrairement à bash,
$0
et ne${.sh.file}
sont PAS garantis pour être exactement identiques dans le cas non-source, comme$0
peut être un chemin relatif , alors qu'il${.sh.file}
s'agit toujours d'un chemin complet , il$0
faut donc le résoudre en chemin complet avant de comparer.zsh
$ZSH_EVAL_CONTEXT
contient des informations sur le contexte d'évaluation - appelez cela en dehors d'une fonction. À l'intérieur d'un script d'origine [portée de niveau supérieur de],$ZSH_EVAL_CONTEXT
se termine par:file
.Caveat: A l' intérieur d' une substitution de commande, zsh ajouter ses
:cmdsubst
, donc essai$ZSH_EVAL_CONTEXT
pour:file:cmdsubst$
là - bas.Utilisation des fonctionnalités POSIX uniquement
Si vous êtes prêt à faire certaines hypothèses, vous pouvez faire une estimation raisonnable, mais non infaillible, de savoir si votre script est d'origine, sur la base de la connaissance des noms de fichiers binaires des shells qui peuvent exécuter votre script .
Cela signifie notamment que cette approche échoue si votre script provient d' un autre script .
La section "Comment gérer les appels provenant de sources" dans ma réponse traite des cas marginaux qui ne peuvent pas être traités avec les fonctionnalités POSIX uniquement en détail.
Cela repose sur le comportement standard de
$0
, quizsh
, par exemple, ne présente pas .Ainsi, l'approche la plus sûre consiste à combiner les méthodes robustes spécifiques au shell ci-dessus avec une solution de secours pour tous les shells restants.
Pointe du chapeau à Stéphane Desneux et sa réponse pour l'inspiration (transformer mon expression de déclaration cross-shell en une déclaration
sh
compatibleif
et ajouter un gestionnaire pour d'autres coquilles).[1] user1902689 a découvert que renvoie
[[ $0 != "$BASH_SOURCE" ]]
un faux positif lorsque vous exécutez un script situé dans le$PATH
en passant son simple nom de fichier aubash
binaire; par exemple,,bash my-script
car$0
est alors justemy-script
, alors que$BASH_SOURCE
c'est le chemin complet . Bien que vous n'utilisiez normalement pas cette technique pour appeler des scripts dans$PATH
- vous les invoqueriez directement (my-script
) - elle est utile lorsqu'elle est combinée avec-x
pour le débogage .la source
Après avoir lu la réponse de @ DennisWilliamson, il y a quelques problèmes, voir ci-dessous:
Cette question étant ksh et frapper, il y a une autre partie de cette réponse concernant ksh... voir ci-dessous.
Facile frapper façon
Essayons (à la volée car ce bash pourrait ;-):
J'utilise
source
plutôt off.
pour plus de lisibilité (comme.
c'est un alias poursource
):Notez que le numéro de processus ne change pas tant que le processus reste source :
Pourquoi ne pas utiliser la
$_ == $0
comparaisonPour assurer de nombreux cas, je commence à écrire un vrai script:
Copiez ceci dans un fichier appelé
testscript
:Maintenant, nous pourrions tester:
C'est bon.
C'est bon.
Mais, pour tester un script avant d'ajouter un
-x
indicateur:Ou pour utiliser des variables prédéfinies:
Cela ne fonctionnera plus.
Déplacer le commentaire de la 5e ligne à la 6e donnerait une réponse plus lisible:
Plus fort: ksh maintenant...
Comme je n'utilise pas ksh beaucoup, après quelques lectures sur la page de manuel, voici mes essais:
Copiez ceci dans un
testfile.ksh
:Ensuite, exécutez-le deux fois:
et voyez:
Il y a une variable héritée dans une analyse d'origine , mais rien de vraiment lié ...
Vous pouvez même vérifier que
$SECONDS
c'est proche0.000
, mais cela garantit que seuls les cas d' origine manuelle ...Vous pouvez même essayer de vérifier ce qu'est le parent:
Placez-le dans votre
testfile.ksh
:Que:
ou
ps ho cmd $PPID
, mais cela ne fonctionne que pour un seul niveau de sous-sessions ...Désolé, je n'ai pas pu trouver un moyen fiable de le faire, sous ksh.
la source
[ "$0" = "$BASH_SOURCE" ] || [ -z "$BASH_SOURCE" ]
pour les scripts lus via pipe (cat script | bash
)..
n'est pas un alias poursource
, c'est en fait l'inverse.source somescript.sh
est un Bash-ism et n'est pas portable,. somescript.sh
est POSIX et IIRC portable.La
BASH_SOURCE[]
réponse (bash-3.0 et versions ultérieures) semble la plus simple, bien qu'elle neBASH_SOURCE[]
soit pas documentée pour fonctionner en dehors d'un corps de fonction (elle fonctionne actuellement, en désaccord avec la page de manuel).Le moyen le plus robuste, comme suggéré par Wirawan Purwanto, est de vérifier
FUNCNAME[1]
au sein d'une fonction :Ensuite:
Cela revient à vérifier la sortie de
caller
, les valeursmain
et àsource
distinguer le contexte de l'appelant. L'utilisationFUNCNAME[]
vous évite de capturer et d'analyser lacaller
sortie. Vous devez cependant connaître ou calculer la profondeur de votre appel local pour être correct. Des cas comme un script provenant d'une autre fonction ou d'un autre script entraîneront un approfondissement du tableau (pile). (FUNCNAME
est une variable de tableau bash spéciale, elle doit avoir des index contigus correspondant à la pile d'appels, tant qu'elle ne l'est jamaisunset
.)(Dans bash-4.2 et versions ultérieures, vous pouvez utiliser le formulaire plus simple à la
${FUNCNAME[-1]}
place pour le dernier élément du tableau. Amélioré et simplifié grâce au commentaire de Dennis Williamson ci-dessous.)Cependant, votre problème, comme indiqué, est " J'ai un script où je ne veux pas qu'il appelle" exit "s'il est d'origine ". L'
bash
idiome commun à cette situation est:Si le script est recherché, il
return
mettra fin au script source et reviendra à l'appelant.Si le script est en cours d'exécution, alors
return
retournera une erreur (redirigée) etexit
terminera le script normalement. Les deuxreturn
etexit
peuvent prendre un code de sortie, si nécessaire.Malheureusement, cela ne fonctionne pas
ksh
(du moins pas dans la version dérivée d'AT & T que j'ai ici), elle est considéréereturn
comme équivalente àexit
si elle est invoquée en dehors d'une fonction ou d'un script source.Mise à jour : ce que vous pouvez faire dans les versions contemporaines de,
ksh
c'est vérifier la variable spéciale.sh.level
qui est définie sur la profondeur d'appel de la fonction. Pour un script appelé, ce paramètre sera initialement non défini, pour un script source de points, il sera défini sur 1.Ce n'est pas aussi robuste que la version bash, vous devez invoquer
issourced()
dans le fichier que vous testez au niveau supérieur ou à une profondeur de fonction connue.(Vous pouvez également être intéressé par ce code sur github qui utilise une
ksh
fonction de discipline et une astuce de piège de débogage pour émuler leFUNCNAME
tableau bash .)La réponse canonique ici: http://mywiki.wooledge.org/BashFAQ/109 offre également un
$-
autre indicateur (bien qu'imparfait) de l'état du shell.Remarques:
FUNCNAME[]
mais tant que seul le dernier élément de ce tableau est testé, il n'y a aucune ambiguïté.pdksh
. La chose la plus proche que je peux trouver ne s'applique qu'àpdksh
, où chaque sourcing d'un script ouvre un nouveau descripteur de fichier (commençant par 10 pour le script d'origine). Ce n'est certainement pas quelque chose sur lequel vous voulez compter ...la source
${FUNCNAME[(( ${#FUNCNAME[@]} - 1 ))]}
d'obtenir le dernier élément (en bas) de la pile? Ensuite, les tests par rapport à "main" (négation pour OP) ont été les plus fiables pour moi.PROMPT_COMMAND
ensemble, cela apparaît comme le dernier index duFUNCNAME
tableau si je courssource sourcetest.sh
. Le chèque inverser (recherchemain
comme le dernier indice) semble plus robuste:is_main() { [[ ${FUNCNAME[@]: -1} == "main" ]]; }
.FUNCNAME
n'est disponible que dans les fonctions. Selon mes tests avecdeclare -p FUNCNAME
,bash
se comporte différemment. v4.3 donne une erreur en dehors des fonctions, alors que v4.4 donnedeclare -a FUNCNAME
. Les deux (!) Retourmain
pour${FUNCNAME[0]}
dans le script principal (si elle est exécutée) tout en$FUNCNAME
ne donne rien. Et: Il y a tellement de scripts "ab" qui utilisent$BASH_SOURCE
des fonctions externes, que je doute que cela puisse ou sera changé.Note de l'éditeur: la solution de cette réponse fonctionne de manière robuste, mais ne l'est que
bash
. Il peut être simplifié(return 2>/dev/null)
.TL; DR
Essayez d'exécuter une
return
instruction. Si le script n'est pas d'origine, cela générera une erreur. Vous pouvez intercepter cette erreur et continuer selon vos besoins.Mettez ceci dans un fichier et appelez-le, disons, test.sh:
Exécutez-le directement:
Source:
Pour moi, cela fonctionne en zsh et bash.
Explication
L'
return
instruction génère une erreur si vous essayez de l'exécuter en dehors d'une fonction ou si le script n'est pas d'origine. Essayez ceci à partir d'une invite shell:Vous n'avez pas besoin de voir ce message d'erreur, vous pouvez donc rediriger la sortie vers dev / null:
Vérifiez maintenant le code de sortie. 0 signifie OK (aucune erreur n'est survenue), 1 signifie qu'une erreur s'est produite:
Vous souhaitez également exécuter l'
return
instruction à l'intérieur d'un sous-shell. Lorsque l'return
instruction l'exécute. . . bien . . . Retour. Si vous l'exécutez dans un sous-shell, il sortira de ce sous-shell, plutôt que de sortir de votre script. Pour exécuter dans le sous-shell, enveloppez-le dans$(...)
:Maintenant, vous pouvez voir le code de sortie du sous-shell, qui devrait être 1, car une erreur a été déclenchée à l'intérieur du sous-shell:
la source
$ readlink $(which sh)
dash
$ . test.sh
This script is sourced.
$ ./test.sh
This script is sourced.
return
doit être fait au niveau supérieur ( pubs.opengroup.org/onlinepubs/9699919799/utilities/… ). Ladash
coque traite unreturn
au niveau supérieur commeexit
. D'autres coquilles aimentbash
ouzsh
n'autorisent pasreturn
au niveau supérieur, ce qui est la caractéristique qu'une technique comme celle-ci exploite.$
avant du sous-shell. Autrement dit, utilisez(return >/dev/null 2>&1)
au lieu de$(return >/dev/null 2>&1)
- mais cela cesse de fonctionner dans bash.dash
, lorsque cette solution ne fonctionne pas, agit commesh
sur Ubuntu, par exemple, cette solution ne fonctionne généralement pas avecsh
. La solution fonctionne pour moi dans Bash 3.2.57 et 4.4.5 - avec ou sans le$
précédent(...)
(bien qu'il n'y ait jamais de bonne raison pour le$
).return
sans aucune valeur de retour explicite ne se casse lors de l’ingénieriesource
des scripts juste après une commande mal exécutée. Proposition de modification de l'amélioration.FWIW, après avoir lu toutes les autres réponses, j'ai trouvé la solution suivante pour moi:
Cela fonctionne pour tous les scripts, qui commencent par
#!/bin/bash
mais qui peuvent également provenir de différents shells pour apprendre certaines informations (comme les paramètres) qui sont conservées en dehors de lamain
fonction.Au lieu des 2 dernières lignes, vous pouvez utiliser le code suivant (à mon avis moins lisible) pour ne pas définir
BASH_SOURCE
dans d'autres shells et permettreset -e
de travailler dansmain
:Cette recette de script a les propriétés suivantes:
S'il est exécuté par
bash
la voie normale,main
est appelé. Veuillez noter que cela n'inclut pas un appel commebash -x script
(oùscript
ne contient pas de chemin), voir ci-dessous.S'il provient de
bash
,main
n'est appelé que si le script appelant se trouve avoir le même nom. (Par exemple, s'il s'approvisionne lui-même ou viabash -c 'someotherscript "$@"' main-script args..
oùmain-script
doit être, ce quitest
apparaît comme$BASH_SOURCE
).S'il provient / est exécuté / lu /
eval
édité par un shell autre quebash
,main
n'est pas appelé (BASH_SOURCE
est toujours différent de$0
).main
n'est pas appelé sibash
lit le script depuis stdin, sauf si vous définissez$0
la chaîne vide comme ceci:( exec -a '' /bin/bash ) <script
Si évalué par
bash
aveceval
(eval "`cat script`"
toutes les citations sont importantes! ) À partir d'un autre script, cela appellemain
. Sieval
est exécuté directement à partir de la ligne de commande, cela est similaire au cas précédent, où le script est lu depuis stdin. (BASH_SOURCE
est vide, alors qu'il$0
est généralement/bin/bash
sinon forcé à quelque chose de complètement différent.)Si
main
n'est pas appelé, il retournetrue
($?=0
).Cela ne repose pas sur un comportement inattendu (auparavant, j'écrivais non documenté, mais je n'ai trouvé aucune documentation que vous ne pouvez
unset
ni modifierBASH_SOURCE
non plus):BASH_SOURCE
est un tableau réservé à bash . Mais permettreBASH_SOURCE=".$0"
de le changer ouvrirait une boîte de vers très dangereuse, donc je m'attends à ce que cela ne produise aucun effet (sauf, peut-être, un avertissement laid apparaîtra dans une future version debash
).BASH_SOURCE
fonctionne en dehors des fonctions. Cependant le contraire (qu'il ne fonctionne que dans les fonctions) n'est ni documenté. L'observation est que cela fonctionne (testé avecbash
v4.3 et v4.4, malheureusement je n'ai plus debash
v3.x) et que trop de scripts se briseraient, s'ils$BASH_SOURCE
cessent de fonctionner comme observé. Par conséquent, je m'attends à ce que celaBASH_SOURCE
reste aussi pour les futures versions debash
.( return 0 )
ce qui donne0
si sourcé et1
si non sourcé. Cela vient un peu inattendu non seulement pour moi , et (selon les lectures là-bas) POSIX dit que lereturn
sous-shell est un comportement indéfini (et lereturn
ici vient clairement d'un sous-shell). Peut-être que cette fonctionnalité finira par être suffisamment utilisée pour ne plus pouvoir être modifiée, mais AFAICS il y a beaucoup plus de chances que certainesbash
versions futures modifient accidentellement le comportement de retour dans ce cas.Malheureusement,
bash -x script 1 2 3
ne fonctionne pasmain
. (Comparezscript 1 2 3
oùscript
n'a pas de chemin). La solution suivante peut être utilisée comme solution de contournement:bash -x "`which script`" 1 2 3
bash -xc '. script' "`which script`" 1 2 3
bash script 1 2 3
ne fonctionne pasmain
peut être considéré comme une fonctionnalité.Notez que les
( exec -a none script )
appelsmain
(bash
ne sont pas transmis$0
au script, pour cela, vous devez les utiliser-c
comme indiqué au dernier point).Ainsi, à l'exception de certains cas de coin,
main
n'est appelé que lorsque le script est exécuté de la manière habituelle. Normalement, c'est ce que vous voulez, surtout parce qu'il manque un code complexe et difficile à comprendre.Pourquoi je pense que c'est une bonne façon générale de résoudre le défi
Si vous avez quelque chose, qui peut provenir de plusieurs shells, il doit être compatible. Cependant (lisez les autres réponses), car il n'y a pas de moyen portable (facile à mettre en œuvre) pour détecter l'
source
ing, vous devez changer les règles .En imposant que le script doit être exécuté par
/bin/bash
, vous faites exactement cela.Cela résout tous les cas, mais les suivants, auquel cas le script ne peut pas s'exécuter directement:
/bin/bash
n'est pas installé ou ne fonctionne pas (i. E. dans un environnement de démarrage)curl https://example.com/script | $SHELL
bash
est suffisamment récente. Cette recette aurait échoué pour certaines variantes. Assurez-vous donc de vérifier qu'elle fonctionne pour votre cas.)Cependant, je ne peux penser à aucune raison réelle pour laquelle vous avez besoin de cela et également à la possibilité de source exactement le même script en parallèle! Habituellement, vous pouvez l'envelopper pour exécuter
main
manuellement. Comme ça:$SHELL -c '. script && main'
{ curl https://example.com/script && echo && echo main; } | $SHELL
$SHELL -c 'eval "`curl https://example.com/script`" && main'
echo 'eval "`curl https://example.com/script`" && main' | $SHELL
Remarques
Cette réponse n'aurait pas été possible sans l'aide de toutes les autres réponses! Même les mauvais - ce qui m'a d'abord fait publier ceci.
Mise à jour: modifiée en raison des nouvelles découvertes trouvées dans https://stackoverflow.com/a/28776166/490291
la source
/bin/sh
est effectivementbash
en mode POSIX, l'affectation àBASH_SOURCE
casse votre script. Dans d' autres coquilles (dash
,ksh
,zsh
), invoquant votre script en passant comme un argument de fichier directement aux exécutables shell dysfonctionnements (par exemple,zsh <your-script>
fera votre script pensent à tort qu'il est sourced ). (Vous mentionnez déjà que le piping du code fonctionne mal, dans tous les shells.). <your-script>
(l'approvisionnement) fonctionne en principe à partir de tous les shells POSIX, cela n'a de sens que si le script a été explicitement écrit pour utiliser uniquement les fonctionnalités POSIX, afin d'empêcher les fonctionnalités spécifiques à un shell de interrompre l'exécution dans d'autres coquilles; utiliser une ligne de Bash Shebang (plutôt que#!/bin/sh
) est donc déroutant - au moins sans commentaire évident. Inversement, si votre script est destiné à être exécuté uniquement à partir de Bash (même si ce n'est qu'en ne tenant pas compte des fonctionnalités qui peuvent ne pas être portables), il est préférable de refuser l' exécution dans des shells autres que Bash.main
, mais il le fait dans ce cas! Et lorsqu'il provient de/bin/sh
ce qui estbash --posix
, la même chose se produit dans ce cas, et c'est tout aussi faux.Cela fonctionne plus tard dans le script et ne dépend pas de la variable _:
ou
la source
Je vais donner une réponse spécifique à BASH. Korn shell, désolé. Supposons que le nom de votre script soit
include2.sh
; puis faites une fonction à l' intérieur de l'include2.sh
appeléam_I_sourced
. Voici ma version de démonstration deinclude2.sh
:Essayez maintenant de l'exécuter de plusieurs façons:
Cela fonctionne donc sans exception, et il n'utilise pas les
$_
choses fragiles . Cette astuce utilise la fonction d'introspection de BASH, c'est-à-dire les variables intégréesFUNCNAME
etBASH_SOURCE
; voir leur documentation dans la page de manuel bash.Seulement deux mises en garde:
1) l'appel à
am_I_called
doit avoir lieu dans le script d'origine, mais pas dans aucune fonction, de peur de${FUNCNAME[1]}
renvoyer autre chose. Ouais ... tu aurais pu vérifier${FUNCNAME[2]}
- mais tu te rends la vie plus difficile.2) la fonction
am_I_called
doit résider dans le script d'origine si vous voulez savoir quel est le nom du fichier inclus.la source
Je voudrais suggérer une petite correction à la réponse très utile de Dennis , pour la rendre légèrement plus portable, j'espère:
parce que
[[
n'est pas reconnu par le ( un peu à mon humble avis anal rémanentes) Debian compatible POSIX shell,dash
. De plus, on peut avoir besoin des guillemets pour se protéger contre les noms de fichiers contenant des espaces, là encore dans ledit shell.la source
$_
est assez fragile. Vous devez le vérifier comme première chose que vous faites dans le script. Et même dans ce cas, il n'est pas garanti de contenir le nom de votre shell (s'il provient) ou le nom du script (s'il est exécuté).Par exemple, si l'utilisateur a défini
BASH_ENV
, alors en haut d'un script,$_
contient le nom de la dernière commande exécutée dans leBASH_ENV
script.La meilleure façon que j'ai trouvée est d'utiliser
$0
comme ceci:Malheureusement, cette méthode ne fonctionne pas dès le départ dans zsh car l'
functionargzero
option fait plus que son nom l'indique et est activée par défaut.Pour contourner cela, j'ai mis
unsetopt functionargzero
mon.zshenv
.la source
J'ai suivi l' expression compacte mklement0 .
C'est bien, mais j'ai remarqué qu'il peut échouer dans le cas de ksh lorsqu'il est appelé comme ceci:
(il pense qu'il est originaire et ce n'est pas parce qu'il exécute un sous-shell) Mais l'expression fonctionnera pour détecter cela:
De plus, même si l'expression est compacte, la syntaxe n'est pas compatible avec tous les shells.
J'ai donc terminé avec le code suivant, qui fonctionne pour bash, zsh, dash et ksh
N'hésitez pas à ajouter le support des coquilles exotiques :)
la source
ksh 93+u
,ksh ./myscript.sh
fonctionne bien pour moi (avec ma déclaration) - quelle version utilisez-vous?/proc/$$/cmdline
) et se concentredash
uniquement sur (qui agit également commesh
sur Ubuntu, par exemple). Si vous êtes prêt à faire certaines hypothèses, vous pouvez$0
rechercher un test raisonnable - mais incomplet - portable.sh
/dash
ainsi, dans un addendum à ma réponse.Je ne pense pas qu'il existe un moyen portable de le faire à la fois dans ksh et bash. En bash, vous pouvez le détecter en utilisant la
caller
sortie, mais je ne pense pas qu'il existe un équivalent dans ksh.la source
$0
travaille dansbash
,ksh93
etpdksh
. Je n'ai pasksh88
à tester.J'avais besoin d'un one-liner qui fonctionne sur [mac, linux] avec bash.version> = 3 et aucune de ces réponses ne correspond à la facture.
la source
bash
solution fonctionne bien (vous pourriez simplifier$BASH_SOURCE
), mais laksh
solution n'est pas robuste: si votre script provient d' un autre script , vous obtiendrez un faux positif.Droit au but: vous devez évaluer si la variable "$ 0" est égale au nom de votre Shell.
Comme ça:
Via SHELL :
Via SOURCE :
Il est assez difficile d'avoir un moyen 100% portable de détecter si un script a été sourcé ou non.
En ce qui concerne mon expérience (7 ans avec Shellscripting) , le seul moyen sûr (ne pas s'appuyer sur des variables d'environnement avec des PID et ainsi de suite, qui n'est pas sûr car c'est quelque chose de VARIABLE ), vous devez:
Les deux options ne peuvent pas être mises à l'échelle automatiquement, mais c'est la manière la plus sûre.
Par exemple:
lorsque vous sourcez un script via une session SSH, la valeur renvoyée par la variable "$ 0" (lors de l'utilisation de source ) est -bash .
OU
la source
/bin/bash -c '. ./check_source.sh'
donneThe script WAS NOT sourced.
. Même bug:ln -s /bin/bash pumuckl; ./pumuckl -c '. ./check_source.sh'
->The script WAS NOT sourced.
J'ai fini par vérifier
[[ $_ == "$(type -p "$0")" ]]
Lorsqu'il est utilisé
curl ... | bash -s -- ARGS
pour exécuter un script distant à la volée, le $ 0 sera justebash
au lieu de normal/bin/bash
lors de l'exécution du fichier de script réel, donc j'utilisetype -p "$0"
pour afficher le chemin complet de bash.tester:
la source
Ceci est un spin off de quelques autres réponses, concernant le support "universel" de shell croisé. Certes, cela est très similaire à https://stackoverflow.com/a/2942183/3220983 en particulier, bien que légèrement différent. La faiblesse de ceci, c'est qu'un script client doit respecter la façon de l'utiliser (c'est-à-dire en exportant d'abord une variable). La force est que cela est simple et devrait fonctionner "n'importe où". Voici un modèle pour votre plaisir de copier-coller:
Remarque: J'utilise
export
juste être sûr que ce mécanisme peut être étendu en sous-processus.la source