В чем причина странного синтаксиса оператора case в сценарии bash/zsh?

С точки зрения программиста, сценарий оболочки — это просто еще один язык программирования, где нужно учиться и соблюдать правила языка. Однако я должен признать, что этот синтаксис — самый странный стиль, который я когда-либо видел в довольно часто используемом языке. Взял ли оболочка этот синтаксис из более старого языка, от которого она происходит? Есть ли в синтаксисе особое значение/значение?

В качестве примера, вот небольшой фрагмент, который я беру из другого сообщения на SO

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

Глядя на это, во-первых, я вижу, что case заканчивается на esac, что является его перевернутой формой (например, if заканчивается на fi). Во-вторых, я понимаю, что за каждым случаем следует ). Справедливо, но зачем мне две ; в конце каждого утверждения? Я бы также сказал, что ) без сопровождающего ( уродливо.

Я ищу дополнительную информацию об историческом аспекте языка, но я открыт и по техническим причинам.


person phunehehe    schedule 21.11.2010    source источник
comment
Итак, вы можете догадаться, почему цикл 'for ...; делать ...; сделано», а не «для ...; делать ...; од'? Для этого была веская причина, но перевернутое ключевое слово в стиле Алгола для обозначения конца использовалось в другом месте.   -  person Jonathan Leffler    schedule 21.11.2010
comment
@ Джонатан, я не спорю, почему это так, а не так? (Кажется, я ясно дал понять это в самом начале). Мой вопрос больше похож на то, откуда взялся уродливый синтаксис?   -  person phunehehe    schedule 22.11.2010
comment
Синтаксис исходил от Борна (известного из оболочки Борна). Он работал на Алголе, и ему это понравилось настолько, что он смоделировал некоторые синтаксис оболочки на Алголе. Алгол использует перевернутые ключевые слова, чтобы отметить концы конструкций, поэтому «case ... esac» был уместным. Причина того, что циклы не заканчиваются на «od», заключается в том, что в Unix уже была команда «od» — восьмеричный дамп. Таким образом, вместо этого используется «готово». (И, судя по репутации, исходный код оболочки Bourne был написан на идиосинкразическом C с макросами, чтобы он выглядел как Algol. Это усложняло его поддержку.)   -  person Jonathan Leffler    schedule 22.11.2010
comment
@Jonathan хороший ответ, пожалуйста :)   -  person phunehehe    schedule 22.11.2010


Ответы (4)


По запросу:

  • Итак, можете ли вы догадаться, почему цикл «for ...; do ...; done», а не «for ...; do ...; od»? Для этого была веская причина, но перевернутое ключевое слово в стиле Алгола для обозначения конца использовалось в другом месте.

Отвечать:

  • Синтаксис исходил от Борна (известного из оболочки Борна). Он работал на Алголе, и ему это понравилось настолько, что он смоделировал некоторые синтаксис оболочки на Алголе. Алгол использует перевернутые ключевые слова, чтобы отметить концы конструкций, поэтому «case ... esac» был уместным. Причина того, что циклы не заканчиваются на «od», заключается в том, что в Unix уже была команда «od» — восьмеричный дамп. Таким образом, вместо этого используется «готово».

Судя по репутации, исходный код оболочки Bourne был написан на идиосинкразическом C с макросами, делающими его похожим на Algol. Это усложняло обслуживание.

Что касается основного вопроса — почему вокруг альтернатив в утверждении case нет открывающей скобки (круглой скобки) — у меня есть пара связанных теорий.

Прежде всего, когда была написана оболочка Bourne (конец 1970-х), много редактирования было сделано с помощью 'ed', стандартный текстовый редактор. В нем нет концепции перехода к сбалансированной скобке или другим подобным обозначениям, поэтому не было необходимости в ведущей скобке. Кроме того, если вы пишете документ, вы можете упорядочить свои аргументы с помощью:

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

Открывающая скобка часто опускается, и оператор case прекрасно вписался бы в эту модель.

Конечно, с тех пор мы привыкли к редакторам, которые помечают совпадающую открытую скобку, когда вы вводите закрывающую скобку, поэтому старая нотация оболочки Bourne доставляет неудобства. Стандарт POSIX делает ведущую скобку необязательной; большинство более современных реализаций POSIX-подобных оболочек (Korn, Bash, Zsh) будут поддерживать это, и я обычно использую его, когда мне не нужно беспокоиться о переносимости на такие машины, как Solaris 10, где /bin/sh по-прежнему является верным Bourne оболочка, которая не допускает ведущую скобку. (Обычно я справляюсь с этим, используя #!/bin/ksh в качестве шебанга.)

person Jonathan Leffler    schedule 22.11.2010
comment
Я бы сказал, что главный вопрос заключается в происхождении синтаксиса, которым является Алгол (не могу найти его на странице Википедии для bash). В любом случае хороший ответ :) - person phunehehe; 23.11.2010
comment
Информацию об «оригинальной» оболочке Bourne можно найти в проекте Heirloom Bourne Shell на Sourceforge ( и другие места, которые можно найти с помощью вашей любимой поисковой системы). - person Jonathan Leffler; 24.08.2013

Причина использования ;; заключается в том, что один ; может использоваться для записи нескольких операторов в одной строке, например:

restart)
   stop; start;;
...
person khachik    schedule 21.11.2010

Bash может принимать совпадающие круглые скобки:

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

    etc.
person Dennis Williamson    schedule 21.11.2010
comment
Оболочки POSIX и Korn также допускают начальные скобки. Давным-давно ed ("стандартный текстовый редактор" - так было сказано в руководстве UNIX 7-го издания) не имел опции "переместить курсор в соответствие с открывающей скобкой", поэтому в открывающей скобке не было особой необходимости. - person Jonathan Leffler; 21.11.2010
comment
Autoconf и его друзья предпочитают помещать комментарий с соответствующим количеством открытых скобок после in (например, case "$1" in # ((). Это помогает оболочкам, которые не могут обрабатывать обычный оператор case внутри $() и редакторов, как это делает новый синтаксис, но также работает с оригинальной оболочкой Bourne. - person jilles; 22.11.2010
comment
@ Деннис, приятно знать, но это было до или после того, как несоответствующий стиль стал популярным? - person phunehehe; 22.11.2010
comment
@phunehehe: я не знаю, что вы имеете в виду, если вы не хотите знать, была ли когда-нибудь оболочка с case/esac, которая не принимала открывающие скобки. Ответ на это - да. Оригинальная оболочка Bourne — один из примеров. - person Dennis Williamson; 22.11.2010
comment
Нет, я имею в виду, принимал ли bash совпадающие скобки с самого начала? Или это появилось позже, когда кто-то пожаловался на уродство? - person phunehehe; 22.11.2010
comment
@phunehehe: документация для этого изменилась где-то между 2.0 (1996 г.) и 2.05b (2002 г.). Я не знаю, было ли оно принято до того, как оно было задокументировано. CHANGES, похоже, ничего не говорит по этому поводу. - person Dennis Williamson; 22.11.2010
comment
@DennisWilliamson, пожалуйста, помогите с вопросом об операторе bash case. Можно ли его использовать для определения того, набрал ли пользователь скобки? Пример read -p "type an opening or closing parethesis " PAREN; case $PAREN in )) echo "user typed )"; ;; () echo "user typed ("; ;; esac - person MAGA; 25.04.2018
comment
@Sergio: Вам нужно избегать круглых скобок в случаях: read -r -p "type an opening or closing parethesis " PAREN; case "$PAREN" in \)) echo "user typed )"; ;; \() echo "user typed ("; ;; esac, и вы должны иметь привычку почти всегда использовать -r с read и цитировать свои переменные. - person Dennis Williamson; 25.04.2018

Закрывающая скобка иногда используется в списках на естественном языке, например

1) do this
2) do that

Перевернутые ключевые слова были взяты из какой-то формы Алгола, но на самом деле это очень хорошая идея для интерактивного использования. Они четко разграничивают конец конструкции, включая if/else.

Например, с C-подобным синтаксисом после анализа:

if (condition)
    command here;

else придет или нет? rc, оболочка из Plan 9 с более похожим на C синтаксисом, решает эту проблему, предоставляя if not вместо else, но это некрасиво.

С синтаксисом оболочки Bourne у вас будет либо else, либо fi, и нет необходимости читать дополнительный ввод.

person jilles    schedule 21.11.2010
comment
Я понимаю вашу точку зрения о списках, но остальная часть не имеет особого смысла. В любом случае необходимо прочитать дополнительный ввод, чтобы определить, является ли это else или fi. - person phunehehe; 22.11.2010
comment
Но этот дополнительный ввод является частью if. С синтаксисом, подобным C, с else, если нет else, оболочка в конечном итоге читает следующую команду, что довольно неожиданно для интерактивной оболочки. - person jilles; 23.11.2010