¿Hay un shell mínimamente compatible con POSIX.2?
(5)
¿Existe un shell que cumpla con POSIX .2 como mínimo (llamémoslo mpcsh
) en el siguiente sentido:
Si mpcsh myscript.sh
comporta correctamente en mi sistema (compatible), entonces xsh myscript.sh
se comportará de manera idéntica para cualquier shell compatible con xsh
en cualquier sistema compatible. ("De forma idéntica" a cosas menos relevantes como la redacción de los mensajes de error, etc.)
¿ dash califica?
Si no es así, ¿hay alguna forma de verificar el cumplimiento de myscript.sh
?
Si no es así, ¿hay alguna forma de verificar el cumplimiento de myscript.sh?
Este es básicamente un caso de Aseguramiento de la Calidad. Empezar con:
- revisión de código
- pruebas unitarias (si, he hecho esto)
- pruebas funcionales
- realice el conjunto de pruebas con tantos programas shell diferentes como pueda encontrar. (
ash
,bash
,dash
,ksh93
,mksh
,zsh
)
Personalmente, ksh93
al conjunto común de extensiones como son compatibles con bash
y ksh93
. Son los intérpretes más antiguos y más ampliamente disponibles del lenguaje shell disponible.
EDITAR Hace poco me rylnd/shpec con rylnd/shpec , un marco de prueba para su código de shell. Puede describir las características de su código en casos de prueba y especificar cómo se pueden verificar. Revelación: ayudé a que funcionara en bash, ksh y dash.
La triste respuesta por adelantado.
No le servirá de nada (no tanto y de forma fiable como lo esperaría y querrá).
Aquí es por qué.
Un gran problema que no puede resolverse con un "shell POSIX" virtual son las cosas que están redactadas de manera ambigua o que simplemente no se abordan en el estándar, de modo que los shells pueden implementarlo de diferentes maneras sin dejar de cumplir el estándar.
Tomemos estos dos ejemplos con respecto a las tuberías, el primero de los cuales es bien conocido:
Ejemplo 1 - alcance
$ ksh -c ''printf "foo" | read s; echo "[${s}]"''
[foo]
$ bash -c ''printf "foo" | read s; echo "[${s}]"''
[]
ksh
ejecuta el último comando de una tubería en el shell actual, mientras que bash
ejecuta todo, incluido el último comando, en una subshell. bash 4
introdujo la opción lastpipe
que hace que se comporte como ksh
:
$ bash -c ''shopt -s lastpipe; printf "foo" | read s; echo "[${s}]"''
[foo]
Todo esto es (debatably) según el estándar :
Además, cada comando de una canalización de comandos múltiples se encuentra en un entorno de subshell; como extensión, sin embargo, cualquiera o todos los comandos en una tubería pueden ejecutarse en el entorno actual.
No estoy 100% seguro de lo que significaron con extensión , pero en base a otros ejemplos en el documento, no significa que el shell tenga que proporcionar una manera de cambiar entre comportamientos, sino que simplemente puede, si lo desea, implementar cosas. en este "camino extendido". Otras personas leen esto de manera diferente y discuten sobre el comportamiento de ksh
que no cumple con los estándares y puedo ver por qué. No solo la redacción es desafortunada, sino que no es una buena idea permitir esto en primer lugar.
En la práctica, realmente no importa qué comportamiento es correcto, ya que son los "" "dos grandes shells" "" y la gente pensaría que si no usas sus extensiones y solo el código supuestamente compatible con POSIX, funcionará en cualquiera de las dos, pero la verdad es que si confía en uno u otro comportamiento mencionado anteriormente, su secuencia de comandos puede dividirse de manera horrible.
Ejemplo 2 - redirección
Este que aprendí hace unos días, vea mi respuesta here :
foo | bar 2>./qux | quux
El sentido común y POLA me dicen que cuando se golpea la siguiente línea de código, tanto quux
como la bar
deberían haber terminado de ejecutarse, lo que significa que el archivo ./qux
está completamente lleno. ¿Derecha? No.
POSIX declara que
Si la canalización no está en segundo plano (consulte Listas asíncronas), el shell esperará hasta que finalice el último comando especificado en la canalización y también puede esperar a que se completen todos los comandos.)
¡Puede (!) Esperar a que se completen todos los comandos! ¿Qué?
bash espera:
El shell espera a que todos los comandos en la tubería terminen antes de devolver un valor.
pero ksh no lo hace
Cada comando, excepto posiblemente el último, se ejecuta como un proceso separado; el shell espera a que finalice el último comando.
Entonces, si usa la redirección entre tuberías, asegúrese de saber lo que está haciendo, ya que esto se trata de manera diferente y puede romperse horriblemente en los casos de borde, según su código.
Podría dar otro ejemplo no relacionado con tuberías, pero espero que estos dos sean suficientes.
Conclusión
Tener un estándar es bueno, revisarlo continuamente es incluso mejor y adherirse a él es excelente. Pero si el estándar falla debido a la ambigüedad o la permisividad, las cosas todavía pueden romperse de manera inesperada, lo que prácticamente deja sin efecto la utilidad del estándar.
Lo que esto significa en la práctica es que, además de escribir el código "compatible con POSIX", aún debe pensar y saber qué está haciendo para evitar que ocurran ciertas cosas.
Todo lo que se dice, un shell que aún no se ha mencionado es posh
que supuestamente es POSIX y tiene incluso menos extensiones que el dash
(principalmente echo -n
y la palabra clave local
) de acuerdo con su página de manual:
BUGS
Any bugs in posh should be reported via the Debian BTS.
Legitimate bugs are inconsistencies between manpage and behavior,
and inconsistencies between behavior and Debian policy
(currently SUSv3 compliance with the following exceptions:
echo -n, binary -a and -o to test, local scoping).
YMMV.
Actualmente, no hay un modelo de rol único para el POSIX shell
.
Desde el shell Bourne original, el shell POSIX ha adoptado una serie de características adicionales.
Todos los shells que conozco que implementan esas funciones también tienen extensiones que van más allá del conjunto de características del shell POSIX.
Por ejemplo, POSIX permite expresiones aritméticas en el formato:
var=$(( expression ))
pero no permite el equivalente:
(( var = expression ))
soportado por bash
y ksh93
.
Sé que bash
tiene una opción set -o posix
, pero eso no deshabilitará ninguna extensión.
$ set -o posix
$ (( a = 1 + 1 ))
$ echo $a
2
Por lo que yo ksh93
, ksh93
intenta ajustarse a POSIX fuera de la caja, pero aún así permite extensiones.
Los desarrolladores de POSIX pasaron años (no una exageración) luchando con la pregunta: "¿Qué significa que un programa de aplicación se ajuste a la norma?" Mientras que los desarrolladores de POSIX pudieron definir un conjunto de pruebas de conformidad para una implementación de los estándares (POSIX.1 y POSIX.2), y pudieron definir la noción de "aplicación estrictamente conforme" como una que no usó una interfaz más allá de los elementos obligatorios De la norma, no pudieron definir un régimen de prueba que confirmara que un programa de aplicación en particular estaba "estrictamente en conformidad" con POSIX.1, o que un script de shell estaba "en estricta conformidad" con POSIX.2.
La pregunta original busca justamente eso; una prueba de conformidad que verifica que un script usa solo elementos del estándar que están completamente especificados. Por desgracia, el estándar está lleno de "palabras de comadreja" que aflojan las definiciones de comportamiento, haciendo que tal prueba sea efectivamente imposible para un script de cualquier nivel significativo de utilidad. (Esto es cierto incluso dejando de lado el hecho de que los scripts de shell pueden generar y ejecutar scripts de shell, lo que hace que la cuestión de "cumplir estrictamente" sea equivalente al problema de detención).
(Revelación completa: fui miembro activo y líder del comité dentro de IEEE-CS TCOS, los creadores de la familia de estándares POSIX, de 1988 a 1999).
Probablemente, lo más parecido a una concha canónica es la ash
que mantiene la Fundación NetBSD, entre otras organizaciones.
Una variante posterior de esta dash es mejor conocida.