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.
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.
Respuestas:
La razón por la que esto no funciona es porque lo ve -i /bin/sh
como un argumento único para env
. Por lo general, esto sería 2 argumentos, -i
y /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 CLEANED
no se establece la variable de entorno. Luego, en re-exec, establece la variable para asegurarse de que no entre en un bucle.
env
Los GNU coreutils ahora tienen una opción -S
para solucionar problemas similares a este pero no exactamente lo mismo. Por ejemplo #!/usr/bin/env -S perl -T
.
#!/usr/bin/env -S -i /bin/sh
. Tenga en cuenta los problemas de portabilidad.
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 exec
cuando el entorno no está limpio (por ejemplo, $ HOME está definido):
[ "$HOME" != "" ] && exec -c $0
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 -e
y set -u
no 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 -e
configuración.
Probar la HOME
variable 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"
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 perl
con 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 perl
puede agregar más lógica, si es necesario (aunque no mucho en Linux ya que está limitado a BINPRM_BUF_SIZE
caracteres, lo que probablemente sea 128)
Lamentablemente, esto es específico de Linux, no funcionará en un sistema que permita múltiples argumentos shebang: - /
perl
procesa 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, @ARGV
normalmente contiene solo los argumentos y $0
contiene el script, pero con este shebang $ARGV[0]
está el nombre del script (y $0
es -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 -c
argumento adicional ) que el antiguo AT&T ksh93
hace:
#!/bin/ksh /usr/bin/env -i /bin/sh
aunque tal vez ksh
no sea tan común hoy en día ;-)
( bash
tiene 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 exec
usando -a
para hacer ARGV[0]
(y por lo tanto $_
) solo "bash", y usando -c
para 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 unset
las 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.