Quelle est la manière la plus appropriée de distribuer des scripts shell, si les comportements des shells peuvent être modifiés par set
et sont donc imprévisibles?
Par exemple, rm *.txt
ne serait pas exécuté comme prévu sur les environnements dans lesquels il set -f
a été exécuté. Comment dois-je m'assurer que rm *.txt
tous les fichiers texte d'un répertoire actuel sont supprimés dans tous les environnements?
Comment dois-je m'assurer que les scripts shell s'exécuteront comme prévu avant de les distribuer en général?
bash
shell
shell-script
hoge
la source
la source
shell_state=$(set +o)
... script ...eval "$shell_state"
#!
pour spécifier les options de shell que vous souhaitez.Réponses:
Les scripts shell sont normalement traités comme s'ils étaient les mêmes que tout autre type de fichier exécutable, tels que les binaires, les scripts Python, les scripts Perl ou tout autre type de script. Ils ont un shebang en haut qui dirige le noyau pour les exécuter à travers le shell. Ils devraient être invoqués de la même manière que toute autre commande.
En tant que tel, un nouveau shell est démarré chaque fois que le script est appelé, et tous les paramètres tels que ceux
set -f
présents dans le shell appelant ou dans toute autre instance de shell du système ne sont pas pertinents.Bien sûr, il est possible pour les utilisateurs de source votre script au lieu de l'exécuter, par exemple comme ceci:
ou pour l'exécuter dans un shell qui a des paramètres non par défaut comme celui-ci:
mais ceux-ci ne sont pas considérés comme des moyens normaux ou d'invoquer votre script, et les utilisateurs qui le font devraient s'attendre à ce qu'ils obtiennent en conséquence.
Notez qu'il y a des scripts qui sont destinés à être sourcés, non exécutés, car leur but est de faire des choses comme changer le cwd ou définir des variables d'environnement qui doivent être reflétées dans l'environnement du shell de sourcing, mais ce sont en minorité et cela se fait généralement dans le cadre d'un protocole convenu. Ces fichiers peuvent être considérés plus comme des "plugins" pour n'importe quel système dont ils s'attendent à provenir, pas tant que des scripts indépendants. Par exemple, les fichiers
/etc/rc*.d
dont le nom se termine.sh
par proviennent du sous-système de script de démarrage et ne sont pas exécutés, et il est documenté que c'est ce qui se produira si vous placez un fichier portant un tel nom dans/etc/rc*.d
et quand c'est fait, c'est fait exprès. La convention de nommer les fichiers destinés à provenir au lieu d'être exécutés de cette manière est également suivie ailleurs, mais pas universellement.Il est vrai que les fichiers destinés à provenir de cette manière doivent prendre soin des paramètres qui pourraient être présents dans l'environnement de leur appelant et qui pourraient affecter le comportement du shell, mais le protocole convenu devrait alors idéalement promettre un environnement d'exécution prévisible.
la source
zsh
a une fonctionnalité qui permet de restaurer les options dans un ensemble connu dans un contexte local (emulate -L zsh
) qui est largement utilisé dans toutes les extensions livrées avec zsh et écrites en code zsh. Voyez comment le système d'achèvement de bash échoue lamentablement si vous définissez certaines options commefailglob
.#! /bin/csh -f
au lieu de#! /bin/csh
par exemple.zshenv
. Faites attention à ce que vous mettezzshenv
pour cette raison!emulate -L
dans ce cas) en commentant une de mes réponses, et je l'apprécie.~/.zshenv
(où vous voulez forcer les paramètres (généralement les vars env) pour tous les zsh (interactifs ou non) invoqués sous votre nom, et généralement non utilisés sauf pour contourner un autre problème non zsh) est séparé de~/.zshrc
(l'interactif shell de personnalisation), c'est donc une fonctionnalité, pas un bug. (vous pouvez utiliser zsh -f) Un bogue survient lorsque certains shells bash non interactifs lisent votre~/.bashrc
(comme sur ssh et vous devez ajouter du code pour éviter cela), ou certains bash interactifs (ceux de connexion) ne le lisent pas (et encore une fois, vous devez ajouter du code dans votre~/.bash_profile
pour contourner ce problème).