¿Cuál es la razón de la extraña sintaxis de la sentencia "case" en un script bash/zsh?


Mirando desde el punto de vista de un programador, entonces shell script es solo otro lenguaje de programación, donde uno tiene que aprender y ajustarse a las reglas del lenguaje. Sin embargo, tengo que admitir que esta sintaxis es el estilo más extraño que he visto en un lenguaje bastante utilizado. ¿El shell tomó esta sintaxis de un lenguaje antiguo del que desciende? ¿Hay una implicación / significado especial en la sintaxis?

Como ejemplo, aquí hay un pequeño fragmento que tomo de otro post en SO

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        stop
        start
        ;;
    status)
        check_status
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|status}"
        exit 1
        ;;
esac

Mirando esto, en primer lugar, puedo ver que case termina con esac, que es su forma invertida (como if terminados en fi). En segundo lugar entiendo que cada caso es seguido por un ). Bastante justo, pero ¿por qué demonios necesito dos ; al final de cada declaración? También diría que el {[5] } sin un acompañante ( es feo.

Estoy buscando más información sobre el aspecto histórico del lenguaje, pero estoy abierto a los aspectos técnicos razones también.

Author: Community, 2010-11-21

4 answers

Por solicitud:

  • Entonces, ¿puedes adivinar por qué un bucle es 'for ...; do ...; done' y no 'for ...; do ...; od'? Había una buena razón para ello, pero la palabra clave inversa similar a Algol para marcar el final se usó en otros lugares.

Respuesta:

  • La sintaxis vino de Bourne (de Bourne shell fama). Había trabajado en Algol, y le gustó lo suficiente como para modelar parte de la sintaxis de shell en Algol. Algol utiliza palabras clave invertidas para marcar los extremos de las construcciones, por lo que 'case ... esac ' era apropiado. La razón por la que loops do not end with ' od 'is that there was already a command' od ' in Unix - octal dump. Entonces, 'hecho' se usa en su lugar.

Por reputación, el código fuente de Bourne shell fue escrito en C idiosincrásico con macros para que pareciera Algol. Esto hizo que fuera difícil de mantener.

Con respecto a la pregunta principal - acerca de por qué no hay paréntesis de apertura (paréntesis) alrededor de las alternativas en la declaración case - Tengo un par de teorías relacionadas.

En primer lugar, cuando el Bourne shell fue escrito (finales de la década de 1970), mucha edición se hizo con 'ed', el editor de texto estándar . No tiene el concepto de saltar a un paréntesis equilibrado u otras notaciones similares, por lo que no había ningún requisito para un paréntesis inicial. Además, si usted está escribiendo un documento, bien podría organizar sus argumentos con:

a) ...blah...
b) ...more...
c) ...again...

A menudo se omite el paréntesis de apertura, y la declaración case encajaría en ese modelo bastante felizmente.

Por supuesto, desde entonces, se han acostumbrado a los editores que marcan el paréntesis abierto coincidente cuando escribe un paréntesis de cierre, por lo que la antigua notación de Bourne shell es una molestia. El estándar POSIX hace que el paréntesis principal sea opcional; la mayoría de las implementaciones más modernas de shells similares a POSIX (Korn, Bash, Zsh) lo soportarán, y generalmente lo uso cuando no tengo que preocuparme por la portabilidad a máquinas como Solaris 10 donde /bin/sh sigue siendo un shell Bourne fiel que no permite el paréntesis principal. (Me por lo general, tratar con que mediante el uso de #!/bin/ksh como el shebang.)

 30
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-20 17:23:23

La razón de usar ;; es que un solo ; se puede usar para escribir varias sentencias en una línea, como:

restart)
   stop; start;;
...
 17
Author: khachik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-21 20:01:06

Bash puede aceptar paréntesis coincidentes:

case "$1" in
    (start)
        start
        ;;
    (stop)
        stop
        ;;

    etc.
 9
Author: Dennis Williamson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-21 14:59:33

El paréntesis de cierre se usa a veces en listas en lenguaje natural, como

1) do this
2) do that

Las palabras clave invertidas fueron tomadas de alguna forma de Algol, pero son de hecho una muy buena idea para el uso interactivo. Delimitan claramente el final de una construcción, incluyendo si/else.

Por ejemplo, con una sintaxis similar a C, después de que esto se haya analizado:

if (condition)
    command here;

¿Hay un else que viene o no? rc, un shell del Plan 9 con una sintaxis más similar a C, resuelve esto proporcionando if not en lugar de else pero no es bonito.

Con la sintaxis de Bourne shell, tendrá else o fi y no hay necesidad de leer entrada adicional.

 3
Author: jilles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-21 22:37:34