bash / zsh脚本中“case”语句的奇怪语法是什么原因?

时间:2010-11-21 14:28:24

标签: bash shell case zsh

从程序员的角度来看,shell脚本只是另一种编程语言,必须学习并遵守语言规则。但是,我必须承认,这种语法是我在一种常用语言中见过的最奇怪的风格。 shell是否采用了它来自的较旧语言的语法?语法中是否有特殊含义/含义?

举个例子,这是我在{<3}}上从SO

获取的一个小片段
case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        stop
        start
        ;;
    status)
        check_status
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|status}"
        exit 1
        ;;
esac

考虑到这一点,首先我可以看到caseesac结尾,这是其反转形式(如iffi结尾)。其次,我了解每个案例后跟)。很公平,但为什么我在每个陈述的末尾都需要两个;?我还要说)没有伴随(是丑陋的。

我正在寻找有关该语言历史方面的更多信息,但我也是出于技术原因而开放。

4 个答案:

答案 0 :(得分:37)

按要求:

  • 那你能猜出为什么一个循环是'for ...; do ...; done'而不是'for ...; do ...; od'?这有一个合理的理由 - 但在其他地方使用了标记结尾的类似Algol的反向关键字。

答案:

  • 语法来自Bourne(Bourne shell成名)。他曾在Algol工作过,并且非常喜欢在Algol上模拟一些shell语法。 Algol使用反向关键字来标记构造的结尾,所以'case ... esac'是合适的。循环不以'od'结尾的原因是Unix中的命令'od' - 八进制转储。因此,改为使用'done'。

通过声誉,Bourne shell源代码是用特殊的C语言编写的宏,使其看起来像Algol。这使得难以维护。

关于主要问题 - 关于为什么case陈述中的替代方案没有开括号(括号) - 我有几个相关的理论。

首先,回到编写Bourne shell时(20世纪70年代末),使用“ed”,standard text editor进行了大量编辑。它没有跳过平衡括号或其他此类符号的概念,因此不需要前导括号。此外,如果您正在编写文档,则可以使用以下方法编组您的参数:

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

通常省略左括号 - case语句非常适合该模型。

当然,从那时起,我们已经习惯于在键入右括号时标记匹配的左括号的编辑器,因此旧的Bourne shell表示法是一种麻烦。 POSIX标准使前导括号可选;大多数类似POSIX的shell(Korn,Bash,Zsh)的现代实现都会支持它,当我不必担心像Solaris 10这样的机器的可移植性时我通常会使用它,其中/ bin / sh仍然是忠实的Bourne shell不允许前导括号。 (我通常使用#!/bin/ksh作为shebang来解决这个问题。)

答案 1 :(得分:23)

使用;;的原因是可以使用单个;在一行中写入多个语句,例如:

restart)
   stop; start;;
...

答案 2 :(得分:11)

Bash可以接受匹配的括号:

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

    etc.

答案 3 :(得分:3)

右括号有时在自然语言的列表中使用,例如

1) do this
2) do that

反向关键字取自某种形式的Algol,但实际上是交互式使用的一个非常好的主意。它们清楚地划分了构造的结尾,包括if / else。

例如,使用类似C的语法,在解析之后:

if (condition)
    command here;

是否有else即将到来? rc,来自Plan 9的shell,具有更像C语法,通过提供if not代替else来解决这个问题,但它并不漂亮。

使用Bourne shell语法,您将拥有elsefi,并且无需阅读其他输入。