Escribir scripts de shell que se ejecutarán en cualquier shell (¿usando varias líneas shebang?)

19

Acabo de comenzar a profundizar en las secuencias de comandos de shell, y siempre lancé mi secuencia de comandos en un archivo, la marqué chmod +xy luego hice /path/to/script.shy dejé que cualquier intérprete que sea el predeterminado tenga su camino, lo que asumí que era zsh porque eso es lo que Solía ​​para mi caparazón. Aparentemente parece que es solo /bin/shpor defecto, incluso si ejecuto el script desde un indicador de zsh, porque comencé a poner cosas específicas de zsh en mis scripts y falla a menos que lo ejecute zsh /path/to/script.sh.

Para ir al grano, aquí están mis preguntas:

  1. ¿Qué shell ejecuta scripts cuando no hay una línea shebang ( #!/path/to/shell) al principio? Supongo /bin/shpero no puedo confirmar.
  2. ¿Qué se considera "mejores prácticas" en términos de escribir scripts de shell que se ejecutarán en cualquier plataforma? (ok, esto es algo abierto)
  3. ¿Es posible escribir un script que intente usar zsh y vuelva a bash si zsh no está disponible? Traté de poner dos líneas shebang, como a continuación, pero simplemente se produce un error bad interpreter: /bin/zsh: no such file or directorysi lo intento en una máquina sin zsh.

    #!/bin/zsh

    #!/bin/bash

swrobel
fuente

Respuestas:

25

¿Qué shell ejecuta scripts cuando no hay una línea shebang (#! / Path / to / shell) al principio? Asumo / bin / sh pero no puedo confirmar.

El núcleo se niega a ejecutar tales secuencias de comandos y devuelve ENOEXEC, por lo que el comportamiento exacto depende del programa que se ejecuta una secuencia de comandos de .

  • bash 4.2.39 - se usa a sí mismo
  • busybox-ash 1.20.2 - se usa a sí mismo
  • guión 0.5.7 - carreras / bin / sh
  • pescado 1.23.1 - se queja de ENOEXEC, luego culpa al archivo equivocado
  • AT&T ksh 93u + 2012.08.01 - se usa a sí mismo
  • mksh R40f - carreras / bin / sh
  • pdksh 5.2.14 - carreras / bin / sh
  • sh-heirloom 050706 - se usa a sí mismo
  • tcsh 6.18.01 - carreras / bin / sh
  • zsh 5.0.0 - ejecuta / bin / sh
  • cmd.exe 5.1.2600: te mira divertido.

En glibc , funciona execv()o execve()simplemente devuelve ENOEXEC. Pero execvp()oculta este código de error e invoca automáticamente / bin / sh. (Esto está documentado en exec (3p)) .

¿Qué se considera "mejores prácticas" en términos de escribir scripts de shell que se ejecutarán en cualquier plataforma? (ok, esto es algo abierto)

Apéguese a shlas características definidas por POSIX y solo a ellas, o simplemente vaya a bash completo (que está ampliamente disponible) y menciónelo en sus requisitos si lo distribuye.

(Ahora que lo pienso, Perl, o tal vez Python, sería aún más portátil, sin mencionar que tiene una mejor sintaxis).

Siempre agregue la línea shebang. Si usa bash o zsh, use en #!/usr/bin/env bashlugar de codificar la ruta del shell. (Sin embargo, se garantiza que el shell POSIX esté en /bin/sh, así que omita enven ese caso).

(Desafortunadamente, incluso /bin/shno siempre es lo mismo. El programa de autoconfiguración de GNU tiene que lidiar con muchas peculiaridades diferentes ).

¿Es posible escribir un script que intente usar zsh y vuelva a bash si zsh no está disponible? Intenté poner dos líneas shebang, como a continuación, pero solo errores con un mal intérprete: / bin / zsh: no existe tal archivo o directorio si lo intento en una máquina sin zsh.

Solo puede haber una línea shebang; todo después del carácter de nueva línea ni siquiera es leído por el kernel, y tratado por shells.

Es posible escribir un script que se ejecute como #!/bin/sh, comprueba qué shell está disponible y se ejecuta exec zsh "$0" "$@"o exec bash "$0" "$@"depende del resultado. Sin embargo, la sintaxis utilizada por bash y zsh es tan diferente en varios lugares que no recomendaría hacerlo por su propia cordura.

Gravedad
fuente
1
¿Cómo rastreó lo que cada shell llamaba realmente cuando recibió ENOEXEC?
swrobel
2
@SWrobel: Utilizando strace -f -e fork,clone,execve. Algunos proyectiles fueron ejecutados /bin/shdespués del fracaso; otros interpretaron el guión ellos mismos.
Grawity
1
@SWrobel: Otro método es ejecutar un script que consiste en readlink /proc/$$/exe.
Grawity
2
Ver también la respuesta de Stéphane Chazelas a ¿Qué intérprete de shell ejecuta un script sin shebang? (duplicado entre sitios de la subpregunta # 1)
G-Man
1
Para cshy tcsh, el comportamiento depende de si el script comienza con #(en cuyo caso se invocan a sí mismos en lugar de sh para interpretar el script). Eso se remonta a la época en que csh admite comentarios pero no el shell Bourne, por lo que a #fue una pista de que era un script csh.
sch
2

1) El shell actual en el que se está ejecutando (cualquiera que sea el shell)

2) Quédese con el mismo tipo de shell (bash / dash / ash / csh / sea cual sea su sabor) y asegúrese de que sus "plataformas compatibles" instalen el shell que desea utilizar de forma predeterminada. Además, intente utilizar comandos comúnmente disponibles en los sistemas. Evite las opciones específicas de la máquina.

3) No hay realmente una lógica de "si-entonces-otro" para el interpreter directive. Debe especificar un shell que debería existir en todos los sistemas que desea admitir ... es decir, #!/bin/basho especificar un genérico #!/bin/shsiempre que su script sea bastante genérico en todos los shells.

TheCompWiz
fuente