Si los scripts de shell comienzan con #!/bin/bash
, siempre se ejecutarán con bash
from /bin
. Sin embargo, si comienzan con #!/usr/bin/env bash
, buscarán bash
adentro $PATH
y luego comenzarán con el primero que puedan encontrar.
¿Por qué sería útil esto? Suponga que desea ejecutar bash
scripts, que requieren bash 4.xo posterior, pero su sistema solo tiene bash
3.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, ~/bin
por ejemplo. Y también puede modificar su $PATH
variable en su .bash_profile
archivo para incluirla ~/bin
como la primera entrada ( PATH=$HOME/bin:$PATH
ya ~
que no se expandirá $PATH
). Si ahora llama bash
, el shell primero lo buscará $PATH
en orden, por lo que comienza con ~/bin
dónde encontrará su bash
. Lo mismo sucede si los scripts buscan bash
usar #!/usr/bin/env bash
, por lo que estos scripts ahora estarían funcionando en su sistema usando su bash
compilació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 env
es 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 env
lo tanto, buscarán un intérprete llamado <interpreter> <arg>
. Tenga en cuenta que este no es un problema del env
comando 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 sudo
no se configuró para limpiar el entorno o si $PATH
se excluyó de la limpieza. Déjame demostrarte esto:
Por /bin
lo general, es un lugar bien protegido, solo root
es 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 bash
en algún directorio oculto, modificar su .bash_profile
para incluir ese directorio en su $PATH
, de modo que todos los scripts que se utilicen #!/usr/bin/env bash
terminarán ejecutándose con esa falsificación bash
. Si se sudo
mantiene $PATH
, estás en un gran problema.
Por ejemplo, considere que una herramienta crea un archivo ~/.evil/bash
con 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 sudo
guarda $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 /bin
y si no desea colocarlas allí por cualquier razón, realmente no es un problema colocar un enlace simbólico en /bin
esos puntos a sus ubicaciones reales (o tal vez en /bin
sí mismo es un enlace simbólico), por lo que Yo siempre iría con #!/bin/sh
y #!/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/sh
y 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/bin
pero pueden también estar en /usr/local/bin
o en una rama jerarquía completamente diferente ( /opt/...
, /Applications/...
, etc.). Es por eso que a menudo usan la #!/usr/bin/env xxx
sintaxis shebang.