Error shebang de FreeBSD
Me gustaría poner shebang #!/bin/sh -eufo pipefailen mi guión. Pero hay varias cosas extrañas:
- El script fallaría con ese shebang en FreeBSD pero no cuando se ejecuta en MacOS
- en FreeBSd, el mismo shebang funciona cuando se ejecuta directamente desde la línea de comandos (también
/bin/sh).
>>> sh -eufo pipefail -c 'echo hi' # this works
hi
>>> cat <<EOF > script
#!/bin/sh -eufo pipefail
echo hi
EOF
>>> chmod +x ./script
>>> ./script # this doesn't work on FreeBSD but works on MacOS
Illegal option -o ./script
>>> cat ./script
#!/bin/sh -eufo pipefail
echo hi
>>> uname -a
FreeBS 11.3-RELEASE-p7
Respuestas
MacOS aún conserva el antiguo comportamiento de FreeBSD de antes de 2005. En 2005, hubo un cambio importante en la forma en que el kernel de FreeBSD manejaba #!el inicio de un archivo ejecutable transferido execve(), para alinearlo más con algunos otros kernels del sistema operativo. incluyendo Linux y el kernel de NetBSD.
El comentario en el código fuente del kernel de NetBSD intenta pintar esto como un universal:
* recopilar el argumento de la shell. todo después del nombre de la cáscara * se pasa como UN argumento; ese es el correcto (histórico) * comportamiento.-kern/exec-script.c. NetBSD. líneas 189 y siguientes.
En realidad no lo es. Sven Mascheck hizo algunas pruebas hace aproximadamente una década y hay cuatro comportamientos básicos, el AT&T Unix System 5 tiene tanto reclamo de ser un comportamiento "histórico correcto" como el 4.2BSD:
- Ignore los caracteres (antes de 4.2BSD y AT&T Unix System 5).
- Pase toda la cadena en un solo argumento (4.2BSD, NetBSD, Linux y FreeBSD desde 2005 en adelante).
- Divida la cadena por espacios en blanco y páselo como múltiples argumentos (FreeBSD antes de 2005 y MacOS).
- Divida la cadena por espacios en blanco y pase solo el primer argumento (AT&T Unix System 5 y Solaris)
Solo he incluido los sistemas operativos relevantes para esta respuesta entre paréntesis. M. Mascheck verificó mucho más, al igual que Ahmon Dancy en la discusión del Informe de problemas 16393 de FreeBSD. Consulte la lectura adicional para ver las listas completas.
Lo que trajo las cosas a un punto crítico en FreeBSD en 2005 fue que, irónicamente, FreeBSD no era tan simple como eso. Se había introducido un cambio que tenía la intención de hacer que las cosas escritas en libros populares sobre Perl realmente funcionaran: los argumentos se omitían después de un carácter de comentario. Los libros habían recomendado cosas como:
#! / bin / sh - # - * - perl - * -- Larry Wall, Tom Christiansen, Jon Orwant (2000). Programación Perl: 3ª edición . O'Reilly Media. ISBN 9780596000271. pág. 488.
PR 16393 en 2000 era una forma de hacer que el kernel manejara scripts de Perl ejecutables, escritos de la manera que Larry Wall había dicho que funcionaría. Sin embargo, rompió otras cosas y no funcionó por completo.
Hubo algunos idas y venidas sobre esto. Finalmente, en 2005, el mecanismo para hacer que la idea de Larry Wall et al. Funcionara se movió fuera del kernel, que se hizo para comportarse de manera compatible con Linux, NetBSD y 4.2BSD (en lugar de Solaris y AT&T Unix System 5) y se hizo la responsabilidad de sh.
El comportamiento desde 2005 ha sido, por lo tanto, que el shell obtiene tres argumentos, el segundo argumento es la cola completa de la #!línea, e invocar su script directamente con execve()es efectivamente lo mismo que invocar:
sh '-eufo pipefail' ./script
Debería ser bastante obvio por qué el shell de Almquist (que es lo que shestá en FreeBSD) piensa que ese ./scriptes el argumento de opción para la -oopción, y que está tratando la pipefailparte como opciones adicionales de una sola letra recopiladas detrás -(que no tiene alrededor para procesar todavía).
Una alternativa también obvia es tener set -o pipefailcomo primer comando en el script, como se señala enhttps://unix.stackexchange.com/a/533418/5132para el shell Bourne Again . Sin embargo, esto solo se agregó al shell de FreeBSD Almquist en 2019 y, por lo tanto, solo está disponible en versiones muy recientes de FreeBSD. (El shell de Debian Almquist aún no se ha agregado, a partir de 2020).
Otras lecturas
- Indicadores de algunos de los antecedentes históricos: https://unix.stackexchange.com/a/489688/5132
- Sven Mascheck. " Prueba de resultados de varios sistemas ". La
#!magia, detalles sobre el mecanismo shebang / hash-bang en varios sabores de Unix . www.in-ulm.de/~mascheck . - Garance A Drosihn (23 de febrero de 2005). Error en #! procesamiento - Una vez más . lista de correo freebsd-arch.
- ryand (27 de enero de 2000).
/bin/shno quita comentarios en la línea de shebang . Informe de problemas de FreeBSD 16393. - Garance A Drosihn (2005). Nota de actualización para el 28 de mayo de 2005: cambio en el manejo de las opciones del script de shell . people.freebsd.org/~gad.
sh. Manual de Comandos Generales BSD . 2019-02-24. freebsd.org.- Wolfram Schneider (12 de diciembre de 2017). Obtener el estado de salida del proceso que se canaliza a otro:
set -o pipefailfalta para/bin/sh. Informe de problemas de FreeBSD 224270. - Ibrahim Ghazal (30 de junio de 2020). Estado de
set -o pipefail. Lista de correo del shell de Debian Almquist.
Aunque su #!uso no es portátil porque utiliza más que lo simple:
#!/bin/sh
o el único argumento comúnmente soportado como en:
#!/bin/sh -oneflag
El problema real es que está utilizando una opción no portátil -o pipefail.
Esta es una opción de ksh93y bashno es compatible con otros shells.
Antecedentes:
En MacOS,
/bin/shesbashque se ha compilado de una manera específica (por ejemplo, para hacer que las secuencias de escapeechofuncionen de forma predeterminada) para que sea compatible con POSIX. Dado que bash es compatiblepipefail(ver arriba), esto funciona en MacOS.En FreeBSD,
/bin/shesashque no es compatiblepipefail.
Tienes dos posibles caminos por recorrer:
No utilice
set -o pipefailEspere dos años y vuelva a intentarlo. Lo más probable es que esto funcione, porque decidimos agregar esta opción al próximo estándar POSIX (Edición-8) hace 10 meses, consultehttps://www.austingroupbugs.net/view.php?id=789y dado que el próximo estándar POSIX se publicará en aprox. un año, hay una gran posibilidad de que FreeBSD añadirá soporte para
set -o pipefailqueashpronto.