Si los scripts de shell comienzan con #!/bin/bash, siempre se ejecutarán con bashfrom /bin. Sin embargo, si comienzan con #!/usr/bin/env bash, buscarán bashadentro $PATHy luego comenzarán con el primero que puedan encontrar.
¿Por qué sería útil esto? Suponga que desea ejecutar bashscripts, que requieren bash 4.xo posterior, pero su sistema solo tiene bash3.x instalado y actualmente su distribución no ofrece una versión más nueva o no es administrador y no puede cambiar lo que está instalado en ese sistema .
Por supuesto, puede descargar el código fuente de bash y crear su propio bash desde cero, ~/binpor ejemplo. Y también puede modificar su $PATHvariable en su .bash_profilearchivo para incluirla ~/bincomo la primera entrada ( PATH=$HOME/bin:$PATHya ~que no se expandirá $PATH). Si ahora llama bash, el shell primero lo buscará $PATHen orden, por lo que comienza con ~/bindónde encontrará su bash. Lo mismo sucede si los scripts buscan bashusar #!/usr/bin/env bash, por lo que estos scripts ahora estarían funcionando en su sistema usando su bashcompilación personalizada .
Una desventaja es que esto puede conducir a un comportamiento inesperado, por ejemplo, el mismo script en la misma máquina puede ejecutarse con diferentes intérpretes para diferentes entornos o usuarios con diferentes rutas de búsqueda, causando todo tipo de dolores de cabeza.
El mayor inconveniente enves que algunos sistemas solo permitirán un argumento, por lo que no puede hacer esto #!/usr/bin/env <interpreter> <arg>, ya que los sistemas verán <interpreter> <arg>como un solo argumento (lo tratarán como si se citara la expresión) y, por envlo tanto, buscarán un intérprete llamado <interpreter> <arg>. Tenga en cuenta que este no es un problema del envcomando en sí mismo, que siempre permitió pasar múltiples parámetros, pero con el analizador shebang del sistema que analiza esta línea incluso antes de llamar env. Mientras tanto, esto se ha solucionado en la mayoría de los sistemas, pero si su script quiere ser ultra portátil, no puede confiar en que esto se haya solucionado en el sistema que ejecutará.
Incluso puede tener implicaciones de seguridad, por ejemplo, si sudono se configuró para limpiar el entorno o si $PATHse excluyó de la limpieza. Déjame demostrarte esto:
Por /binlo general, es un lugar bien protegido, solo rootes capaz de cambiar algo allí. Sin embargo, su directorio de inicio no es ningún programa que ejecute que pueda realizar cambios en él. Eso significa que el código malicioso podría colocar una falsificación bashen algún directorio oculto, modificar su .bash_profilepara incluir ese directorio en su $PATH, de modo que todos los scripts que se utilicen #!/usr/bin/env bashterminarán ejecutándose con esa falsificación bash. Si se sudomantiene $PATH, estás en un gran problema.
Por ejemplo, considere que una herramienta crea un archivo ~/.evil/bashcon el siguiente contenido:
#!/bin/bash
if [ $EUID -eq 0 ]; then
echo "All your base are belong to us..."
# We are root - do whatever you want to do
fi
/bin/bash "$@"
Hagamos un script simple sample.sh:
#!/usr/bin/env bash
echo "Hello World"
Prueba de concepto (en un sistema donde se sudoguarda $PATH):
$ ./sample.sh
Hello World
$ sudo ./sample.sh
Hello World
$ export PATH="$HOME/.evil:$PATH"
$ ./sample.sh
Hello World
$ sudo ./sample.sh
All your base are belong to us...
Hello World
Por lo general, las conchas clásicas deben ubicarse todas /biny si no desea colocarlas allí por cualquier razón, realmente no es un problema colocar un enlace simbólico en /binesos puntos a sus ubicaciones reales (o tal vez en /binsí mismo es un enlace simbólico), por lo que Yo siempre iría con #!/bin/shy #!/bin/bash. Hay demasiado que se rompería si esto ya no funcionara. No es que POSIX requiera esta posición (POSIX no estandariza los nombres de ruta y, por lo tanto, ni siquiera estandariza la función shebang), sino que son tan comunes que incluso si un sistema no ofreciera un /bin/sh, probablemente todavía entendería #!/bin/shy saber qué hacer con él y solo puede ser por compatibilidad con el código existente.
Pero para intérpretes opcionales más modernos, no estándar, como Perl, PHP, Python o Ruby, en realidad no se especifica en ningún lugar donde deberían ubicarse. Pueden estar en /usr/binpero pueden también estar en /usr/local/bino en una rama jerarquía completamente diferente ( /opt/..., /Applications/..., etc.). Es por eso que a menudo usan la #!/usr/bin/env xxxsintaxis shebang.