¿Cómo iniciar un script con un entorno limpio?


15

Intenté lo siguiente pero no parece funcionar:

$ cat script.sh
#!/bin/env -i /bin/sh

/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.

Encontré preguntas similares pero no muestra cómo hacerlo desde shebang: unix.stackexchange.com/questions/48994/…
balki

55
No puedes hacerlo desde shebang. El shebang solo puede aceptar un argumento.
jordanm

Respuestas:


7

La razón por la que esto no funciona es porque lo ve -i /bin/shcomo un argumento único para env. Por lo general, esto sería 2 argumentos, -iy /bin/sh. Esto es solo una limitación del shebang. No hay forma de evitarlo.


Sin embargo, aún puede realizar esta tarea, solo de una manera diferente.

Si desea que el script mismo realice esta tarea, y no tiene que hacer algo así env -i script.sh, puede hacer que el script se vuelva a ejecutar.

#!/bin/sh
[ -z "$CLEANED" ] && exec /bin/env -i CLEANED=1 /bin/sh "$0" "$@"

Esto hará que el script se vuelva a ejecutar solo si CLEANEDno se establece la variable de entorno. Luego, en re-exec, establece la variable para asegurarse de que no entre en un bucle.


envLos GNU coreutils ahora tienen una opción -Spara solucionar problemas similares a este pero no exactamente lo mismo. Por ejemplo #!/usr/bin/env -S perl -T.
Weijun Zhou

Acabo de tratar. Funciona para la pregunta original también. Solo úsalo #!/usr/bin/env -S -i /bin/sh. Tenga en cuenta los problemas de portabilidad.
Weijun Zhou

3

Ejecute su script con env -i:

env -i script.sh

Y el guión como siempre:

#!/bin/sh
# ... your code here

Si quieres correr con un entorno limpio sin decirlo explícitamente cuando corres. Eduardo Ivanec da algunas ideas en esta respuesta , puede llamar recursivamente a su script execcuando el entorno no está limpio (por ejemplo, $ HOME está definido):

[ "$HOME" != "" ] && exec -c $0

Agradable. Simplemente no haga env -i bash como lo hice y luego me pregunto por qué sus variables env todavía están configuradas (por supuesto, bash resources .bashrc y amigos 8)
Neil McGill

2

Con bash, puedes hacerlo así:

#!/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

Los comandos set -ey set -uno son estrictamente necesarios, pero los incluyo para demostrar que este enfoque no se basa en acceder a variables no establecidas (como, por ejemplo, lo [ "$HOME" != "" ]haría) y es compatible con una set -econfiguración.

Probar la HOMEvariable debería ser seguro porque bash ejecuta scripts en modo no interactivo, es decir, los archivos de configuración como ~/.bashrc(donde se pueden establecer variables de entorno) no se obtienen durante el inicio.

Salida de ejemplo:

declare -x OLDPWD
declare -x PWD="/home/juser"
declare -x SHLVL="1"

0

$ cat script.sh

#!/bin/env -i /bin/sh

Lamentablemente, no funcionará de esa manera: Linux lo considera -i /bin/shcomo un argumento para pasar env(ver Shebang ).


0

La limitación shebang de 2 argumentos de Linux (interpeter + argumento único) se observa en la mayoría de las respuestas, pero decir que esto no se puede hacer es incorrecto: solo necesita cambiar a un intérprete que pueda hacer algo útil con un solo argumento:

#!/usr/bin/perl -we%ENV=();exec "/bin/sh " . join " ", map "'$_'", @ARGV;
# your sh script here

Lo que esto hace es invocar perlcon un script de una línea ( -e) que borra %ENV(más barato que env -i) e invoca exec /bin/sh, citando correctamente los argumentos. Se perlpuede agregar más lógica, si es necesario (aunque no mucho en Linux ya que está limitado a BINPRM_BUF_SIZEcaracteres, lo que probablemente sea 128)

Lamentablemente, esto es específico de Linux, no funcionará en un sistema que permita múltiples argumentos shebang: - /

perlprocesa esta cadena como un argumento único, por lo que no se cita arriba como lo haría normalmente perl -e ...desde la línea de comando (si agregara comillas, estas se conservan, perl ve solo una cadena literal, con advertencias sobre ella se quejará de una inutilidad constante).

También tenga en cuenta que hay un ligero cambio en el comportamiento cuando se usa de esta manera, @ARGVnormalmente contiene solo los argumentos y $0contiene el script, pero con este shebang $ARGV[0]está el nombre del script (y $0es -e) que lo hace un poco más fácil.

También puede resolver esto con un intérprete que "reprocese" su línea de comando (sin un -cargumento adicional ) que el antiguo AT&T ksh93hace:

#!/bin/ksh /usr/bin/env -i /bin/sh

aunque tal vez kshno sea tan común hoy en día ;-)

( bashtiene una característica similar con --wordexp, pero es "indocumentada" en las versiones donde funciona, y no está habilitada en el momento de la compilación en las versiones donde está documentada: - / Tampoco puede usarse para esto ya que necesita dos argumentos. ..)

Además, efectivamente una variación en las respuestas de @Patrick y @ maxschlepzig:

#!/bin/bash
[ "$_" != bash ] && exec -c -a "bash" /bin/bash "$0" "$@"
# your script here

En lugar de usar una nueva variable, esta usa la variable especial " _", si no está configurada exactamente como "bash", entonces reemplace el script execusando -apara hacer ARGV[0](y por lo tanto $_) solo "bash", y usando -cpara limpiar el entorno.

Alternativamente, si es aceptable limpiar el entorno al comienzo del script (solo bash):

#!/bin/sh
unset $(compgen -e)
# your script here

Eso usa compgen(ayudante de finalización) para enumerar los nombres de todas las variables de entorno exportadas, y unsetlas envía de una vez.

Consulte también Múltiples argumentos en shebang para obtener más detalles sobre el problema general del comportamiento shebang.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.