GNU/Linux >> Tutoriales Linux >  >> Linux

#!/bin/sh vs #!/bin/bash para máxima portabilidad

Solución 1:

Hay aproximadamente cuatro niveles de portabilidad para los scripts de shell (en lo que respecta a la línea shebang):

  1. Más portátil:use un #!/bin/sh shebang y usar solo la sintaxis básica de shell especificada en el estándar POSIX. Esto debería funcionar en prácticamente cualquier sistema POSIX/unix/linux. (Bueno, excepto Solaris 10 y anteriores, que tenían el shell Bourne heredado real, anterior a POSIX, por lo que no cumple, como /bin/sh .)

  2. Segundo más portátil:use un #!/bin/bash (o #!/usr/bin/env bash ) shebang line, y adhiérase a las características de bash v3. Esto funcionará en cualquier sistema que tenga bash (en la ubicación esperada).

  3. Tercero más portátil:use un #!/bin/bash (o #!/usr/bin/env bash ) shebang line, y use las características de bash v4. Esto fallará en cualquier sistema que tenga bash v3 (por ejemplo, macOS, que tiene que usarlo por razones de licencia).

  4. Menos portátil:use un #!/bin/sh shebang y use extensiones bash para la sintaxis de shell POSIX. Esto fallará en cualquier sistema que tenga algo que no sea bash para /bin/sh (como las versiones recientes de Ubuntu). Nunca hagas esto; no es solo un problema de compatibilidad, es simplemente incorrecto. Lamentablemente, es un error que comete mucha gente.

Mi recomendación:use el más conservador de los tres primeros que proporciona todas las funciones de shell que necesita para el script. Para una portabilidad máxima, use la opción n.° 1, pero según mi experiencia, algunas características de bash (como matrices) son lo suficientemente útiles como para optar por la n.° 2.

Lo peor que puedes hacer es #4, usar el shebang incorrecto. Si no está seguro de qué características son POSIX básicas y cuáles son extensiones bash, siga con bash shebang (es decir, la opción n. ° 2) o pruebe el script a fondo con un shell muy básico (como dash en sus servidores Ubuntu LTS). El wiki de Ubuntu tiene una buena lista de bashisms a tener en cuenta.

Hay muy buena información sobre la historia y las diferencias entre los shells en la pregunta de Unix y Linux "¿Qué significa ser compatible con sh?" y la pregunta de Stackoverflow "Diferencia entre sh y bash".

Además, tenga en cuenta que el shell no es lo único que difiere entre los diferentes sistemas; si está acostumbrado a Linux, está acostumbrado a los comandos GNU, que tienen muchas extensiones no estándar que quizás no encuentre en otros sistemas Unix (por ejemplo, bsd, macOS). Desafortunadamente, no existe una regla simple aquí, solo debe conocer el rango de variación de los comandos que está utilizando.

Uno de los comandos más desagradables en términos de portabilidad es uno de los más básicos:echo . Cada vez que lo use con cualquier opción (por ejemplo, echo -n o echo -e ), o con escapes (barras invertidas) en la cadena para imprimir, diferentes versiones harán cosas diferentes. Cada vez que desee imprimir una cadena sin salto de línea después, o con escapes en la cadena, use printf en su lugar (y aprende cómo funciona, es más complicado que echo es). El ps el comando también es un desastre.

Otra cosa general a tener en cuenta son las extensiones recientes/GNUish a la sintaxis de la opción de comando:el formato de comando antiguo (estándar) es que el comando va seguido de opciones (con un solo guión, y cada opción es una sola letra), seguido de argumentos de comando. Las variantes recientes (y a menudo no portátiles) incluyen opciones largas (generalmente introducidas con -- ), permitiendo que las opciones vengan después de los argumentos y usando -- para separar las opciones de los argumentos.

Solución 2:

En el ./configure script que prepara el lenguaje TXR para la construcción, escribí el siguiente prólogo para una mejor portabilidad. El script se iniciará incluso si #!/bin/sh es un antiguo Bourne Shell que no cumple con POSIX. (Desarrolla cada versión en una máquina virtual Solaris 10).

#!/bin/sh

# use your own variable name instead of txr_shell;
# adjust to taste: search for your favorite shells

if test x$txr_shell = x ; then
  for shell in /bin/bash /usr/bin/bash /usr/xpg4/bin/sh ; do
    if test -x $shell ; then
       txr_shell=$shell
       break
    fi
  done
  if test x$txr_shell = x ; then
    echo "No known POSIX shell found: falling back on /bin/sh, which may not work"
    txr_shell=/bin/sh
  fi
  export txr_shell
  exec $txr_shell $0 ${@+"[email protected]"}
fi

# rest of the script here, executing in upgraded shell

La idea aquí es que encontremos un shell mejor que el que estamos ejecutando y volvamos a ejecutar el script usando ese shell. El txr_shell se establece la variable de entorno, de modo que el script reejecutado sepa que es la instancia recursiva reejecutada.

(En mi script, el txr_shell La variable también se usa posteriormente, exactamente con dos propósitos:en primer lugar, se imprime como parte de un mensaje informativo en la salida del script. En segundo lugar, se instala como SHELL variable en el Makefile , de modo que make usará este shell también para ejecutar recetas).

En un sistema donde /bin/sh es guión, puede ver que la lógica anterior encontrará /bin/bash y vuelva a ejecutar el script con eso.

En una caja de Solaris 10, el /usr/xpg4/bin/sh se activará si no se encuentra Bash.

El prólogo está escrito en un dialecto de shell conservador, usando test para pruebas de existencia de archivos, y el ${@+"[email protected]"} truco para expandir argumentos que atienden a algunos viejos shells rotos (que simplemente serían "[email protected]" si estuviéramos en un shell conforme a POSIX).

Solución 3:

Todas las variaciones del lenguaje de shell Bourne son objetivamente terribles en comparación con los lenguajes de secuencias de comandos modernos como Perl, Python, Ruby, node.js e incluso (posiblemente) Tcl. Si tiene que hacer algo, aunque sea un poco complicado, será más feliz a largo plazo si usa uno de los anteriores en lugar de un script de shell.

La única ventaja que tiene el lenguaje shell sobre los lenguajes más nuevos es que algo llamándose a sí mismo /bin/sh está garantizado que existe en cualquier cosa que pretenda ser Unix. Sin embargo, es posible que ese algo ni siquiera sea compatible con POSIX; muchos de los Unix propietarios heredados congelaron el lenguaje implementado por /bin/sh y las utilidades en el PATH predeterminado previo a los cambios exigidos por Unix95 (sí, Unix95, hace veinte años y contando). Puede haber un conjunto de Unix95, o incluso POSIX.1-2001 si tiene suerte, herramientas en un directorio no en la RUTA predeterminada (por ejemplo, /usr/xpg4/bin ) pero no se garantiza que existan.

Sin embargo, los conceptos básicos de Perl son más probables estar presente en una instalación de Unix seleccionada arbitrariamente que Bash. (Por "los fundamentos de Perl" me refiero a /usr/bin/perl existe y es algo , posiblemente bastante antigua, versión de Perl 5 y, si tiene suerte, también está disponible el conjunto de módulos que se incluyeron con esa versión del intérprete.)

Por lo tanto:

Si está escribiendo algo que tiene que funcionar en todas partes que pretende ser Unix (como un script de "configuración"), debe usar #! /bin/sh , y no necesita usar ninguna extensión en absoluto. Hoy en día escribiría un shell compatible con POSIX.1-2001 en esta circunstancia, pero estaría preparado para parchear los POSIXismos si alguien pidiera soporte para hierro oxidado.

Pero si no escribiendo algo que tiene que funcionar en todas partes, entonces, en el momento en que se sienta tentado a usar Bashism, debe detenerse y reescribir todo en un mejor lenguaje de secuencias de comandos. Tu futuro yo te lo agradecerá.

(Así que cuando es ¿Es apropiado usar extensiones de Bash? A primer orden:nunca. A segundo orden:solo para extender el entorno interactivo de Bash, p. para proporcionar una finalización inteligente de pestañas y avisos elegantes).


Linux
  1. ¿Cómo maneja Linux múltiples separadores de rutas consecutivas (/home////username///file)?

  2. Linux – ¿Fusionar /usr/bin y /usr/sbin en /bin (gnu/linux)?

  3. fundamentos de grep

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

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

¿Qué es diferente entre /bin/false y /sbin/nologin como shell del usuario nologin?

permiso denegado para el compositor en /usr/local/bin/

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

Diferencia entre /bin y /usr/bin

¿Deberían vivir los sitios web en /var/ o /usr/ según el uso recomendado?

chroot falla:no se puede ejecutar el comando '/bin/bash':no ​​existe tal archivo o directorio