Existe-t-il un moyen pour source
un script shell dans un espace de noms, de préférence un script shell bash mais je chercherais dans d'autres shells s'ils avaient cette fonctionnalité et bash n'en avait pas.
Ce que je veux dire par là, par exemple, quelque chose comme "préfixe tous les symboles définis avec quelque chose afin qu'ils n'entrent pas en collision avec des symboles déjà définis (noms de variables, noms de fonction, alias)" ou toute autre fonction qui empêche les collisions de noms.
S'il y a une solution où je peux nommer l' espace de source
temps ( NodeJS
style), ce serait le meilleur.
Exemple de code:
$ echo 'hi(){ echo Hello, world; }' > english.sh
$ echo 'hi(){ echo Ahoj, světe; }' > czech.sh
$ . english.sh
$ hi
#=> Hello, world
$ . czech.sh #bash doesn't even warn me that `hi` is being overwritten here
$ hi
#=> Ahoj, světe
#Can't use the English hi now
#And sourcing the appropriate file before each invocation wouldn't be very efficient
( easiest thing ever )
. Mais ce n'est pas tout à fait ce que vous recherchez. Je suppose que vous pourriez faire( stuff in subshell; exec env ) | sed 's/^/namespace_/'
eteval
le résultat dans le shell parent, mais c'est un peu méchant.ksh93
. Les espaces de noms sont fondamentaux pour lui - et tous ses types de noms (qui sont également typables) prennent en charge l'espace de noms. C'est aussi beaucoup plus rapide à pratiquement tous égards quebash
, soit dit en passant.env | sed ...
fonctionnerait pour les variables, je pourrais faireset
pour obtenir des fonctions, mais la recherche et le remplacement seraient un problème - les fonctions peuvent s'appeler et vous devez donc remplacer toutes les invocations croisées par des invocations croisées préfixées mais sans remplacer le mêmes mots ailleurs dans le code de définition de fonction, où ce n'est pas une invocation. Pour cela, vous auriez besoin d'un analyseur bash, pas seulement d'une expression régulière, et cela ne fonctionnerait que tant que les fonctions ne s'appelleraient pas via eval.Réponses:
Depuis
man ksh
un système sur lequel estksh93
installé ...Et, pour le démontrer, voici le concept appliqué à un espace de noms fourni par défaut pour chaque variable shell régulière affectée dans un
ksh93
shell. Dans l'exemple suivant, je définirai unediscipline
fonction qui agira comme la.get
méthode affectée à la$PS1
variable shell. Chaque variable shell obtient essentiellement son propre espace de noms avec, au moins, la valeur par défautget
,set
,append
etunset
méthodes. Après avoir défini la fonction suivante, à chaque fois que la variable$PS1
est référencée dans le shell, la sortie dedate
sera dessinée en haut de l'écran ...(Notez également l'absence de
()
sous - shell dans la substitution de commandes ci-dessus)Techniquement, les espaces de noms et les disciplines ne sont pas exactement la même chose (car les disciplines peuvent être définies pour s'appliquer globalement ou localement à un espace de noms particulier ) , mais elles font à la fois partie intégrante de la conceptualisation des types de données shell qui est fondamentale pour
ksh93
.Pour répondre à vos exemples particuliers:
...ou...
la source
J'ai écrit une fonction shell POSIX qui pourrait être utilisé pour l' espace de noms localement une commande du shell ou une fonction dans l' un des
ksh93
,dash
,mksh
oubash
(nommé spécifiquement parce que je l' ai personnellement confirmé au travail dans tous ces) . Parmi les coques dans lesquelles je l'ai testé, il n'a pas répondu à mes attentesyash
et je ne m'attendais pas du tout à ce qu'il fonctionnezsh
. Je n'ai pas testéposh
. J'ai abandonné tout espoir il y aposh
un moment et je ne l'ai pas installé depuis un certain temps. Peut-être que cela fonctionne enposh
...?Je dis que c'est POSIX parce que, par ma lecture de la spécification, il profite d'un comportement spécifié d'un utilitaire de base, mais, certes, la spécification est vague à cet égard, et, au moins une personne est apparemment en désaccord avec moi. En général, j'ai eu un désaccord avec celui-ci, j'ai finalement trouvé que l'erreur était la mienne, et peut-être que je me trompe également cette fois sur les spécifications, mais quand je l'ai interrogé davantage, il n'a pas répondu.
Comme je l'ai dit, cependant, cela fonctionne certainement dans les coquilles susmentionnées, et cela fonctionne, essentiellement, de la manière suivante:
La
command
commande est spécifiée comme un utilitaire fondamentalement disponible et l'un des pré$PATH
-intégrés. L'une de ses fonctions spécifiées consiste à envelopper des utilitaires intégrés spéciaux dans son propre environnement lors de leur appel, et ainsi de suite ...... le comportement des deux affectations de ligne de commande ci-dessus est correct selon les spécifications. Le comportement des deux conditions d'erreur est également correct et y est en fait presque entièrement reproduit à partir de la spécification. Les affectations préfixées aux lignes de commande des fonctions ou des fonctions spéciales sont spécifiées pour affecter l'environnement shell actuel. De même, les erreurs de redirection sont spécifiées comme fatales lorsqu'elles sont pointées vers l'une ou l'autre.
command
est spécifié pour supprimer le traitement spécial des constructions spéciales dans ces cas, et le cas de redirection est réellement démontré par l'exemple dans la spécification.D'un
command
autre côté, les buildins réguliers sont spécifiés pour s'exécuter dans un environnement de sous - shell - ce qui ne signifie pas nécessairement celui d' un autre processus , juste qu'il devrait être fondamentalement indiscernable d'un. Les résultats de l'appel d'un buildin normal devraient toujours ressembler à ce qui pourrait être obtenu à partir d'une$PATH
commande de capacité similaire . Et donc...Mais la
command
commande ne peut pas appeler les fonctions shell, et ne peut donc pas être utilisée pour rendre leur traitement spécial sans objet comme cela peut être le cas pour les fonctions intégrées normales. C'est également spécifié. En fait, la spécification indique qu'un utilitaire principal decommand
est que vous pouvez l'utiliser dans une fonction shell wrapper nommée pour une autre commande pour appeler cette autre commande sans auto-récursivité car elle n'appellera pas la fonction. Comme ça:Si vous ne l'utilisiez pas
command
, lacd
fonction serait presque définitivement un défaut d'auto-récursivité.Mais en tant que fonction interne standard qui peut appeler des fonctions spéciales, cela
command
peut être fait dans un environnement de sous - shell . Ainsi, alors que shell état actuel défini dans bâton pourrait à la coquille actuelle - certainementread
« s$var1
et$var2
a - au moins les résultats de la ligne de commande définit probablement ne devrait pas ...Maintenant, que
command
la capacité de ou non d'être à la fois un buildin standard et d'appeler directement des builds spéciaux soit juste une sorte d'échappatoire inattendue en ce qui concerne la ligne de commande, je ne sais pas, mais je sais qu'au moins les quatre shells sont déjà mentionné honorer l'command
espace de noms.Et bien
command
qu'il ne puisse pas appeler directement les fonctions shell, il peut appelereval
comme démontré, et peut donc le faire indirectement. J'ai donc construit un wrapper d'espace de noms sur ce concept. Il prend une liste d'arguments comme:... sauf que le
command
mot ci-dessus n'est reconnu comme un que s'il peut être trouvé avec un vide$PATH
. En plus des variables shell-cadrage appelé localement sur la ligne de commande, localement-champs d' application également toutes variables avec des noms simples alphabétiques minuscules et une liste d'autres les standards, tels que$PS3
,$PS4
,$OPTARG
,$OPTIND
,$IFS
,$PATH
,$PWD
,$OLDPWD
et quelques autres.Et oui, en limitant la portée localement la
$PWD
et les$OLDPWD
variables et ensuite explicitementcd
à accepter d'$OLDPWD
et$PWD
il peut assez fiable portée le répertoire de travail actuel ainsi. Ce n'est pas garanti, bien qu'il essaie assez fort. Il conserve un descripteur pour7<.
et lorsque sa cible de retour revient, il le faitcd -P /dev/fd/7/
. Si le répertoire de travail actuel a étéunlink()
dans l'intervalle, il devrait au moins réussir à y revenir mais émettra une erreur laide dans ce cas. Et parce qu'il maintient le descripteur, je ne pense pas qu'un noyau sain d'esprit ne devrait pas non plus pouvoir démonter son périphérique racine (???) .Il étend également localement les options du shell et les restaure dans l'état dans lequel il les a trouvées lorsque son utilitaire encapsulé revient. Il traite
$OPTS
spécialement en ce qu'il conserve une copie dans sa propre portée dont il attribue initialement la valeur$-
. Après avoir également géré toutes les affectations sur la ligne de commande, il le feraset -$OPTS
juste avant d'appeler sa cible de bouclage. De cette façon, si vous définissez-$OPTS
sur la ligne de commande, vous pouvez définir les options de shell de votre cible d'habillage. Lorsque la cible revient, elle vaset +$- -$OPTS
avec sa propre copie de$OPTS
(qui n'est pas affectée par la ligne de commande définie) et tout restaurer à l'état d'origine.Bien sûr, rien n'empêche l'appelant de
returrn
sortir explicitement de la fonction d'une manière ou d'une autre par le biais de la cible de bouclage ou de ses arguments. Cela empêchera toute restauration / nettoyage d'état qu'il tenterait autrement.Pour faire tout ce qu'il faut, il faut aller à trois
eval
. D'abord, il s'enveloppe dans une portée locale, puis, de l'intérieur, il lit les arguments, les valide pour les noms de shell valides et quitte avec erreur s'il en trouve un qui ne l'est pas. Si tous les arguments sont valides et finalement une causecommand -v "$1"
renvoie true (rappel:$PATH
est vide à ce stade) ,eval
la ligne de commande définit et transmet tous les arguments restants à la cible de bouclage (bien qu'elle ignore le cas spécial dens
- car cela ne pas très utile, et troiseval
s de profondeur est plus que suffisant) .Cela fonctionne essentiellement comme ceci:
Il y a quelques autres, et redirections et quelques tests étranges à faire avec la façon dont certains obus mis
c
en$-
puis refusent de l' accepter comme une optionset
(???) , mais son tout accessoire, et principalement utilisés pour économiser d'émettre sortie indésirable et similaire dans les cas de bord. Et c'est comme ça que ça marche. Il peut faire ces choses car il configure sa propre portée locale avant d'appeler son utilitaire encapsulé dans un tel imbriqué.C'est long, car j'essaie d'être très prudent ici - trois,
evals
c'est dur. Mais avec cela, vous pouvez faire:Aller plus loin et espacer de manière persistante la portée locale de l'utilitaire encapsulé ne devrait pas être très difficile. Et même tel qu'il est écrit, il définit déjà une
$LOCALS
variable pour l'utilitaire encapsulé qui se compose uniquement d'une liste séparée par des espaces de tous les noms qu'il a définis dans l'environnement de l'utilitaire encapsulé.Comme:
... qui est parfaitement sûr -
$IFS
a été nettoyé à sa valeur par défaut et seuls les noms de shell valides en font partie,$LOCALS
sauf si vous le définissez vous-même sur la ligne de commande. Et même s'il peut y avoir des caractères globaux dans une variable divisée, vous pouvez également définirOPTS=f
sur la ligne de commande pour que l'utilitaire encapsulé interdise leur expansion. Dans tout les cas:Et voici la fonction. Toutes les commandes sont préfixées w /
\
pour éviter lesalias
extensions:la source