J'ai essayé ce qui suit mais cela ne semble pas fonctionner:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
J'ai essayé ce qui suit mais cela ne semble pas fonctionner:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Réponses:
La raison pour laquelle cela ne fonctionne pas est qu'il considère -i /bin/sh
comme un argument unique à env
. Habituellement, ce serait 2 arguments, -i
et /bin/sh
. Ce n'est qu'une limitation du shebang. Pas question.
Cependant, vous pouvez toujours effectuer cette tâche, d'une manière différente.
Si vous voulez que cette tâche soit exécutée par le script lui-même et que vous n'ayez pas à faire quelque chose comme cela env -i script.sh
, vous pouvez demander au script de se réexécuter lui-même.
#!/bin/sh
[ -z "$CLEANED" ] && exec /bin/env -i CLEANED=1 /bin/sh "$0" "$@"
Cela entraînera le script à se réexécuter si la CLEANED
variable d'environnement n'est pas définie. Ensuite, lors de la réexécution, il définit la variable pour s'assurer qu'elle n'entre pas dans une boucle.
env
des coreutils GNU ont maintenant une option -S
pour contourner les problèmes similaires à celui-ci mais pas exactement les mêmes. Par exemple #!/usr/bin/env -S perl -T
.
#!/usr/bin/env -S -i /bin/sh
. Soyez conscient des problèmes de portabilité.
Exécutez votre script avec env -i
:
env -i script.sh
Et le script comme d'habitude:
#!/bin/sh
# ... your code here
Si vous voulez exécuter avec un environnement propre sans le dire explicitement lorsque vous exécutez. Eduardo Ivanec donne quelques idées dans cette réponse , vous pouvez appeler récursivement votre script exec
lorsque l'environnement n'est pas propre (par exemple $ HOME est défini):
[ "$HOME" != "" ] && exec -c $0
Avec bash, vous pouvez le faire comme ceci:
#!/usr/bin/bash
set -e
set -u
[ -v HOME ] && exec -c "$0" "$@"
# continue with the rest of the script
# e.g. print the cleaned environment:
export
Les commandes set -e
et set -u
ne sont pas strictement nécessaires, mais je les inclue pour démontrer que cette approche ne repose pas sur l'accès aux variables non définies (comme par exemple le [ "$HOME" != "" ]
ferait) et est compatible avec un set -e
paramètre.
Le test de la HOME
variable doit être sûr car bash exécute des scripts en mode non interactif, c'est-à-dire que les fichiers de configuration comme ~/.bashrc
(où les variables d'environnement peuvent être définies) ne sont pas fournis lors du démarrage.
Exemple de sortie:
declare -x OLDPWD
declare -x PWD="/home/juser"
declare -x SHLVL="1"
La limitation de shebang à 2 arguments Linux (interpètre + argument unique) est notée dans la plupart des réponses, mais dire que cela ne peut pas être fait est incorrect - il vous suffit de passer à un interpréteur qui peut faire quelque chose d'utile avec un seul argument:
#!/usr/bin/perl -we%ENV=();exec "/bin/sh " . join " ", map "'$_'", @ARGV;
# your sh script here
Ce que cela fait, c'est invoquer perl
avec un script à une ligne ( -e
) qui efface %ENV
(moins cher que env -i
) et invoque exec /bin/sh
, en citant correctement les arguments. Plus loinperl
logique peut être ajoutée, si nécessaire (mais pas beaucoup sur Linux car vous êtes limité aux BINPRM_BUF_SIZE
caractères, ce qui est probablement 128)
Malheureusement, ceci est spécifique à Linux, cela ne fonctionnera pas sur un système qui autorise plusieurs arguments shebang: - /
perl
traite cette chaîne comme un seul argument, elle n'est donc pas citée ci-dessus comme vous le feriez normalement avecperl -e ...
la ligne de commande (si vous deviez ajouter des guillemets, ceux-ci sont conservés, perl ne voit qu'une chaîne littérale, avec des avertissements dessus, il se plaindra d'une inutilité constant).
Notez également qu'il y a un léger changement de comportement lorsqu'il est utilisé de cette façon, @ARGV
contient normalement uniquement les arguments et $0
contient le script, mais avec ce shebang $ARGV[0]
est le nom du script (et$0
est -e
) ce qui le rend un peu plus facile.
Vous pouvez également résoudre ce problème avec un interpréteur qui "retire" sa ligne de commande (sans -c
argument supplémentaire ) que l'ancien AT&T ksh93
fait:
#!/bin/ksh /usr/bin/env -i /bin/sh
mais peut-être ksh
n'est - pas aussi courant de nos jours ;-)
( bash
a une fonctionnalité similaire avec --wordexp
, mais il est "non documenté" dans les versions où il fonctionne, et n'est pas activé au moment de la compilation dans les versions où il est documenté: - / Il ne peut pas non plus être utilisé pour cela car il a besoin de deux arguments. ..)
Aussi, effectivement une variation sur les réponses de @Patrick et @ maxschlepzig:
#!/bin/bash
[ "$_" != bash ] && exec -c -a "bash" /bin/bash "$0" "$@"
# your script here
Plutôt que d'utiliser une nouvelle variable, cela utilise la variable spéciale " _
", si elle n'est pas définie sur exactement "bash", remplacez le script en exec
utilisant -a
pour faire ARGV[0]
(et donc $_
) juste "bash", et en utilisant-c
pour effacer l'environnement.
Alternativement, s'il est acceptable de nettoyer l'environnement au début du script (bash uniquement):
#!/bin/sh
unset $(compgen -e)
# your script here
Qui utilise compgen
(aide à l'achèvement) pour répertorier les noms de toutes les variables d'environnement exportées, etunset
s en une seule fois.
Voir aussi Arguments multiples dans shebang pour plus de détails sur le problème général du comportement de shebang.