У чому полягає використання дужок `()` у визначенні функції оболонки?


20

Функція визначається як:

do_something () {
    do it
}

Я міг зрозуміти його назву "do_something" і фігурну дужку, щоб інкапсулювати код дій, але я не в змозі зрозуміти, у чому тут мета (), оскільки в сценаріях Bash немає іменованих параметрів. Це може бути краще і простіше визначити як

do_something {
  do it
}

Що не суперечить його поточному синтаксису, а ще більше заявляє про відсутність названих параметрів. Яке тут використання ()?


Відповіді:


44

Без цього ()синтаксис дійсно був би неоднозначним.

Має бути якийсь однозначний синтаксис для визначення функції, і без істотної зміни синтаксису інших оболонок не може бути цього:

do_something {
    # one or more commands go here
}

Ви сказали, що це "не конфліктує з його нинішнім синтаксисом", але це так! Зауважте, що при спробі запуску першого рядка у вас не виникає помилок синтаксису . Ви отримуєте помилку, але це не помилка синтаксису. Другий рядок, з }, є синтаксичною помилкою, але перший рядок - ні. Натомість do_something {спроби запустити команду, що викликається, do_somethingі передати її {як аргумент:

$ do_something {
do_something: command not found

Якщо вже є команда, яка називається do_something, ви її виконуєте. Якщо функція вже називається do_something, ви її викликаєте . Загалом важливо, щоб синтаксис був однозначним, але також важливо конкретно, щоб можна було переосмислити функцію, не випадково викликавши її замість неї. Визначення функції та виклик її не повинно виглядати однаково.

Як лікує шкаралупу {і (.

Як type {вам скажу, {це ключове слово оболонки. Це робить його подібним [[. Якщо використовується в ситуації, коли це інакше було б командою, {несе особливу семантику. Зокрема, воно виконує групування команд. В інших ситуаціях, однак, він може використовуватися без націлювання для позначення буквального {символу. Сюди входить ситуація передачі його як другого або наступного слова команди.

Звичайно, Баш міг бути розроблений так, щоб поводитися {інакше, ніж зараз. Однак його синтаксис тоді б більше не був сумісний з оболонкою POSIX, і Bash насправді не був би оболонкою в стилі Bourne і не міг би запускати багато скриптів оболонок.

Навпаки, (це метахарактер оболонки. Він завжди ставився особливо , якщо він з'являється в команді і не котирується (з ' ', " "або \). Таким чином, у синтаксисі немає двозначності:

do_something() {
    # one or more commands go here
}

Це не могло означати нічого іншого. Якщо у Bash не було функцій, то це була б синтаксична помилка, з тієї ж причини echo foo(bar)- синтаксична помилка.

Якщо ви дійсно не любите ()позначення, то ви можете використовувати ключове слово functionі пропустити його, як згадує sudodus . Зауважте, що це не є частиною синтаксису для визначення функцій у більшості інших оболонок стилю Борна - а в деяких він підтримується, але функції, визначені таким чином, мають різну семантику - і тому сценарій, який використовує його, не буде переносним. (Причина цього синтаксису може бути однозначною - functionце саме ключове слово в Bash, яке означає, що все, що випливає, - це початок визначення функції.)

Нарешті, зауважте, що хоча більшість визначень функцій використовують {на практиці, будь-яка складна команда дозволена. Якби у вас була функція, тіло якої ви хотіли завжди запускати в нижній частині корпусу, ви могли скористатися, ( )а не використовувати { }.


1
На більш високому рівні йдеться про очікування та читабельність людини. У більшості мов, особливо у C, fortran та інших, поширених на час розробки мов сценаріїв bash, функція / підпрограма завжди містить список аргументів, можливо, порожній, це додається в круглі дужки. Змініть цю парадигму, і ви ускладните розуміння мови.
jamesqf

15

()Лексема сказати інтерпретатор оболонки , який ви оголошуєте функцію.

$ do_something () { echo 'do it'; } ; do_something
do it

Альтернативою в bashєfunction

function do_something {
 echo 'do it'
}

або як однолінійний ви можете протестувати

$ bash -c "function do_something { echo 'do it'; } ; do_something"
do it

2
functionКлючове слово є попередньо POSIX КШ-Ізмаїл , що Баш опори для забезпечення сумісності; однак, bash його погано підтримує (не робить змінних function-local default, як старий ksh робив у функціях, оголошених у цій формі). Отже, це не ідеально для нового коду. Дивіться wiki.bash-hackers.org/scripting/obsolete
Чарльз Даффі

@CharlesDuffy, дякую за це пояснення :-)
sudodus

1
@CharlesDuffy Ти кажеш, ksh та bash приймають якийсь синтаксис, який робить змінну локальною в ksh, але глобальною в bash? Це не звучить правильно. Моє розуміння, що частково базується на цій публікації та перевірці (в ksh93), полягає в тому, що ksh робить змінні локальними в меншій кількості ситуацій, ніж bash, ніколи більше. У bash, typesetбез -gфункції завжди оголошується локальна змінна. З functionключовими словами, bash і ksh змінні області однаково , чи не так?
Елія Каган

@EliahKagan Я думаю , що Чарльз був посиланням на це було продемонстровано в відповідь Жиль в тут
Сергій Kolodyazhnyy

9

Як дуже один-справжній-брекет-стиль- вам!

Розглянемо інші, ідеально стильні брекет-стилі:

foo
{
  ...
}
foo
  {
    ...
  }
foo
  while ...; do ...; done # Look, ma! No braces!
foo
( ... ) # Look, ma! No braces and a subshell to boot!

Як оболонка може сказати, що це визначення функцій, а не просто команда, fooза якою слідують списки команд? У всіх цих випадках необхідний додатковий однозначний фактор, наприклад, ()або functionключове слово.


По-друге, це насправді не OTBS, оскільки одне місце, де OTBS дозволяє дужки в новому рядку, призначене для визначення функцій.
муру

3
Я думаю, що слід зробити аргумент, що ви мали рацію охарактеризувати його як OTBS, оскільки на відміну від функцій у C та C ++, визначення функції у сценарії оболонки у стилі Борна може бути вкладено безпосередньо в тіло іншого визначення функції та так, можливо не заслуговує на те, щоб відрізнятись. (Або, можливо, це стиль, популярний у програмуванні Java, де методи отримують діаграму відкриття на одній лінії, а не OTBS.) Так чи інакше, ви чудово розумієте, як синтаксис повинен накладати жорсткі обмеження на розміщення дужок для роботи. зовсім без ()або щось подібне.
Елія Каган
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.