Use #! / Bin / sh o #! / Bin / bash para la compatibilidad y facilidad de uso de Ubuntu-OSX y POSIX

18

Sé que puedo usarlo como la primera línea de scripts para invocar el shell deseado.

¿ #!/bin/shSe recomendaría si la compatibilidad con todos los sistemas Unix es un requisito absoluto?

En mi caso, el único sistema operativo que me importa son Ubuntu (Debian) y OSX. Dado eso, ¿podría usar #!/bin/bashy estar seguro de que funcionaría en ambos sistemas?
¿Esto también facilitaría el uso de scripts con una sintaxis más moderna y clara para los comandos? ¿El uso #!/bin/shtambién se relaciona con el uso de POSIX?

Michael Durrant
fuente
1
Probablemente vale la pena señalar que muchas distribuciones han comenzado a fusionarse /biny /usr/bin. Como resultado, es probable que sea mejor usar #!/usr/bin/env <shname>para la portabilidad en estos días.
HalosGhost

Respuestas:

15

Para empezar, si puede suponer que Bash está preinstalado (que, que yo sepa, es el caso en todos los sistemas que enumera), use el siguiente hashbang para ser compatible:

#!/usr/bin/env bash

Esto invoca cualquier cosa bashque esté configurada, sin importar si está en /bino /usr/local/bin.

Mientras que en la mayoría de los sistemas en una amplia gama (incluidos AIX, Solaris, varios sabores BSD), bashterminaron en diferentes ubicaciones, envsiempre terminaron en /usr/bin/env. Sin embargo, el truco no es mío, sino del autor del Bash Cookbook.

De todos modos, sí, Bash te permitiría usar algunas características "modernas" que te facilitarán la vida.

Por ejemplo los corchetes dobles:

[[ -f "/etc/debian_version" ]] && echo "This is a Debian flavor"

mientras que en los dialectos de concha tradicionales tendrías que recurrir a:

test -f "/etc/debian_version" && echo "This is a Debian flavor"

pero lo mejor de los corchetes dobles es que permiten expresiones regulares para la coincidencia. El Bash hackers Wiki le dará muchos trucos en esa dirección.

También puede usar expresiones bastante convenientes como $((2**10))u otras expresiones aritméticas en línea con la $((expression))sintaxis.

Usar backticks para subshells está bien, aunque un poco desactualizado. Pero las capacidades de anidación de las $(command ...)invocaciones son mucho más convenientes, ya que no tendrá que escapar de muchas cosas en diferentes niveles de subshell.

Estas son solo algunas de las cosas que Bash le brinda sobre la shsintaxis POSIX común tradicional .

Pero si desea más potencia en el shell (no solo en scripts), también eche un vistazo zsh.

0xC0000022L
fuente
Bash es una herramienta muy útil, pero tenga cuidado de no usarla para iniciar servicios que puedan ser vulnerables a un error de scripting de Bash, por ejemplo, access.redhat.com/security/cve/CVE-2014-6271 . Cumplir con shtales tareas.
Rick-777
1
Rick-777 esa vulnerabilidad fue exagerada y, en mi opinión, su comentario es FUD. Si un servicio del sistema se ejecuta bajo bash, de ninguna manera es vulnerable a ese error. Solo es vulnerable a ese error si bifurca un proceso bash mientras permite a los usuarios remotos acceso directo a una o más variables de entorno, como en FastCGI, e incluso en versiones no parcheadas de bash. En sistemas con shenlaces a bash, la vulnerabilidad no se mitigará mediante el uso sh.
Score_Under
11

En Debian y Ubuntu, /bin/shes dash, que es un shell compatible con POSIX. Si especifica #!/bin/sh, debe limitarse a las declaraciones POSIX en su secuencia de comandos. (La ventaja es que dashcomienza más rápido que bash, por lo que su script puede hacer su trabajo en menos tiempo).

En muchos (¿la mayoría?) Otros sistemas Linux, /bin/shes bashpor eso que muchos scripts se escriben #!/bin/shcomo su línea shebang a pesar de que usan bashextensiones.

Si desea usar bashextensiones, el enfoque más seguro en todos los sistemas es especificar #!/bin/bash; de esa manera estás declarando explícitamente tu dependencia bash. Usted necesita hacer esto en Debian y Ubuntu. Como beneficio adicional, cuando se inicia como /bin/sh bashdesactiva algunas extensiones (consulte la descripción del bashmodo POSIX para más detalles); Por lo tanto, #!/bin/bashes necesario especificar para obtener el máximo beneficio de bash.

En OS X también /bin/bashestá disponible, y lo /bin/shes bash. Especificar #!/bin/bashfuncionará bien allí también.

Stephen Kitt
fuente
5

Sí, vendrán OSX y Linux /bin/bash. Deberías estar perfectamente seguro. Sin embargo, eso no es POSIX. El shell POSIX se encuentra en la /bin/shmayoría de los sistemas (¿todos?) Y ese es el enfoque más portátil y la única forma de ser compatible con POSIX.

Tenga en cuenta que si bien en muchos sistemas /bin/shapunta a bash, en otros puede apuntar a diferentes shells. Es un enlace simbólico a dashDebian y Ubuntu, por ejemplo. Además, incluso si se /bin/shtrata de un enlace bash, el comportamiento del shell cambia cuando se lo llama como sh(de man bash, énfasis mío):

Si se invoca bash con el nombre sh, intenta imitar el comportamiento de inicio de las versiones históricas de sh lo más fielmente posible, a la vez que se ajusta al estándar POSIX. Cuando se invoca como un shell de inicio de sesión interactivo o un shell no interactivo con la opción --login, primero intenta leer y ejecutar comandos desde / etc / profile y ~ / .profile, en ese orden. La opción --noprofile puede usarse para inhibir este comportamiento. Cuando se invoca como un shell interactivo con el nombre sh, bash busca la variable ENV, expande su valor si es
definido, y utiliza el valor expandido como el nombre de un archivo para leer y ejecutar. Dado que un shell invocado como sh no intenta leer y ejecutar comandos desde ningún otro archivo de inicio, la opción --rcfile no tiene ningún efecto. Un shell no interactivo invocado con el nombre sh no intenta leer ningún otro archivo de inicio. Cuando se invoca como sh, bash entra en modo posix después de leer los archivos de inicio.

terdon
fuente
2

Si la compatibilidad con "todos los sistemas Unix" es un requisito absoluto, y si no lo es, ¿por qué está escribiendo un script de shell? - entonces, sí, deberías estar usando #! /bin/sh, porque Bash no está garantizado para instalarse en cualquier lugar , y mucho menos en /bin.

En realidad es mucho, mucho peor que eso. Si necesita compatibilidad con todos los sistemas Unix, eso incluye cosas como Solaris y AIX que congelaron sus entornos de shell alrededor de 1995. Lo que significa que debe usar cosas como la sort +Nsintaxis antigua : ¡ los sistemas más nuevos se han caído! Y también significa que no hay funciones de shell, ni matrices, no [[ ... ]], no ${foo#glob}, no $(( ... ))para aritmética, posiblemente $( ... )sustitución de comandos sin estilo, límites superiores pequeños e indocumentados sobre cómo puede obtener una gran entrada, ...

Usted probablemente puede salirse con sin molestarse en que tanto la compatibilidad, pero si es aún un problema, en primer lugar, le recomiendo se tiene en cuenta un lenguaje que es menos terrible que la cáscara. Es más probable que el intérprete básico de Perl esté disponible que Bash.

zwol
fuente
Gracias. Como se dijo originalmente "En mi caso, el único sistema operativo que me importa son Ubuntu (Debian) y OSX". Estos son los únicos 2 sistemas que he usado (y los uso mucho) en los últimos 5 años, por lo que es 'por qué' estoy escribiendo un script de shell que solo funcionaría en ellos. No tengo ninguna necesidad de un guión universal y las limitaciones que presentaría.
Michael Durrant
@MichaelDurrant En ese caso, no necesita y no debe escribir un script de shell. En su lugar, debe usar cualquiera de la multitud de mejores lenguajes de secuencias de comandos que son una opción cuando no necesita portabilidad total.
zwol