GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cuál es la diferencia entre #!/usr/bin/env bash y #!/usr/bin/bash?

Si los scripts de shell comienzan con #!/bin/bash , siempre se ejecutarán con bash de /bin . Sin embargo, si comienzan con #!/usr/bin/env bash , buscarán bash en $PATH y luego comenzar con el primero que puedan encontrar.

¿Por qué esto sería útil? Suponga que desea ejecutar bash scripts, que requieren bash 4.x o 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, colocándolo en ~/bin por ejemplo. Y también puedes modificar tu $PATH variable en su .bash_profile archivo para incluir ~/bin como la primera entrada (PATH=$HOME/bin:$PATH como ~ no se expandirá en $PATH ). Si ahora llamas al bash , el shell primero lo buscará en $PATH en orden, por lo que comienza con ~/bin , donde encontrará su bash . Lo mismo sucede si los scripts buscan bash usando #!/usr/bin/env bash , por lo que estos scripts ahora estarían funcionando en su sistema usando su bash personalizado construir.

Una desventaja es que esto puede conducir a un comportamiento inesperado, p. 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 con 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 argumento (lo tratarán como si la expresión estuviera entrecomillada) y, por lo tanto, env buscará un intérprete llamado <interpreter> <arg> . Tenga en cuenta que esto 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 a env . Mientras tanto, esto se solucionó en la mayoría de los sistemas, pero si su secuencia de comandos quiere ser ultraportátil, no puede confiar en que se haya solucionado en el sistema que ejecutará.

Incluso puede tener implicaciones de seguridad, p. si sudo no estaba configurado para limpiar el entorno o $PATH fue excluido de la limpieza. Déjame demostrarte esto:

Normalmente /bin es un lugar bien protegido, solo root es capaz de cambiar cualquier cosa allí. Sin embargo, su directorio de inicio no es, ningún programa que ejecute puede realizar cambios en él. Eso significa que el código malicioso podría colocar un bash falso en algún directorio oculto, modifica tu .bash_profile para incluir ese directorio en su $PATH , por lo que todos los scripts usan #!/usr/bin/env bash terminará corriendo con ese falso bash . Si sudo mantiene $PATH , estás en un gran problema.

P.ej. 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 "[email protected]"

Hagamos un script simple sample.sh :

#!/usr/bin/env bash

echo "Hello World"

Prueba de concepto (en un sistema donde sudo mantiene $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 estar todas ubicadas en /bin y si no desea colocarlos allí por cualquier motivo, realmente no es un problema colocar un enlace simbólico en /bin que apunta a sus ubicaciones reales (o tal vez /bin en sí mismo es un enlace simbólico), por lo que siempre iría con #!/bin/sh y #!/bin/bash . Hay demasiado que se rompería si estos ya no funcionaran. No es que POSIX requiera estas posiciones (POSIX no estandariza los nombres de las rutas y, por lo tanto, ni siquiera estandariza la función shebang en absoluto), pero son tan comunes que incluso si un sistema no ofrecería un /bin/sh , probablemente todavía entendería #!/bin/sh y saber qué hacer con él y que solo sea 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 también pueden estar en /usr/local/bin o en una rama de jerarquía completamente diferente (/opt/... , /Applications/... , etc.). Es por eso que a menudo usan el #!/usr/bin/env xxx sintaxis shebang.


Usando #!/usr/bin/env NAME hace que el shell busque la primera coincidencia de NOMBRE en la variable de entorno $PATH. Puede ser útil si no conoce la ruta absoluta o no desea buscarla.


Ejecutando un comando a través de /usr/bin/env tiene la ventaja de buscar la versión predeterminada del programa en su env actual planchado.

De esta manera, no tiene que buscarlo en un lugar específico del sistema, ya que esas rutas pueden estar en diferentes ubicaciones en diferentes sistemas. Mientras esté en tu camino, lo encontrará.

Una desventaja es que no podrá pasar más de un argumento (por ejemplo, no podrá escribir /usr/bin/env awk -f ) si desea admitir Linux, ya que POSIX es vago sobre cómo se debe interpretar la línea, y Linux interpreta todo lo que está después del primer espacio para indicar un único argumento. Puedes usar /usr/bin/env -S en algunas versiones de env para evitar esto, pero luego el script se volverá aún menos portátil y se romperá en sistemas bastante recientes (por ejemplo, incluso Ubuntu 16.04 si no es posterior).

Otro inconveniente es que, dado que no está llamando a un ejecutable explícito, tiene la posibilidad de errores y problemas de seguridad en sistemas multiusuario (si alguien logró obtener su ejecutable llamado bash en tu camino, por ejemplo).

#!/usr/bin/env bash #lends you some flexibility on different systems
#!/usr/bin/bash     #gives you explicit control on a given system of what executable is called

En algunas situaciones, se puede preferir el primero (como ejecutar secuencias de comandos de python con varias versiones de python, sin tener que volver a trabajar en la línea ejecutable). Pero en situaciones donde la seguridad es el enfoque, se preferirá lo último, ya que limita las posibilidades de inyección de código.


Linux
  1. Bash =~ Regex y Https://regex101.com/?

  2. ¿Cuál es la diferencia entre /sbin/nologin y /bin/false?

  3. ¿Alguna razón para tener un Shebang apuntando a /bin/sh en lugar de /bin/bash?

  4. cmake --version apunta a /usr/bin/cmake mientras que cmake apunta a /usr/local/bin

  5. Se movió el contenido de /bin a /usr/bin, ¿es posible deshacerlo?

¿Por qué /bin/sh apunta a /bin/dash y no a /bin/bash?

Instalar binarios en /bin, /sbin, /usr/bin y /usr/sbin, interacciones con --prefix y DESTDIR

¿Cuáles son los significados de /usr/sbin, /usr/local/sbin y /usr/local/bin?

¿Cuándo debo usar #!/bin/bash y cuándo #!/bin/sh?

Diferencia entre /bin y /usr/bin

¿Cuál es la diferencia entre /tmp y /run?