різниця між "функцією foo () {}" і "foo () {}"


96

Я можу визначати bashфункції, використовуючи або пропускаючи functionключове слово. Чи є різниця?

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar

Обидва дзвінки до функцій fooі barуспішні, і я не бачу різниці. Тож мені цікаво, чи просто для поліпшення читабельності чи щось мені не вистачає ...

BTW в інших оболонках, як-от dash( /bin/shпосилається на dashdebian / ubuntu), не працює при використанні functionключового слова.


8
Крім того, з або без дужок: function baz { echo "baz"; }. Дивіться башизм у вікі GreyCat.
манатство

Відповіді:


42

Немає різниці AFAIK, крім того, що друга версія є більш портативною.


32
Це велика різниця, портативність ... Я бачу занадто багато відповідей, які просто НЕ працюють на (старих) виробничих системах, а також багато з опціями, які працюють лише на Linux. Принаймні, попередити, що це не самий портативний спосіб ... Це може бути прямо небезпечним (попросити когось, tar cf - /some/thing | ssh user@desthost "cd destinationdir && tar xf - " не попереджаючи їх, щоб попередньо перевірити, чи не позбудеться версія "tar" на desthost "/" катастрофи в деяких випадках ...). Наприклад: якщо використовувати function tar { #a safe tar with safety checks ... }і shігнорує його, ...
Олів'є Дулак,

1
@OlivierDulac Я б додав, що сценарії, які передбачають, що shрозпізнає functionключове слово - і взагалі, які передбачають загальні, але нестандартні функції, які оболонки люблять kshі bashпропонують - також часто не працюватимуть на новіших виробничих системах, навіть якщо вони працювали над старими версіями та ж ОС. bashяк і раніше забезпечує shна багатьох системах GNU / Linux, але деякі популярні дистрибутиви перейшли до того , shяк лінк до dash(в Debian Альмквіст SHell) для підвищення продуктивності. Сюди входять Debian і Ubuntu .
Елія Каган

2
Не уточнюючи, наскільки саме це "більш портативно", відповідь не корисна.
ivan_pozdeev

На сьогодні портативність не є аргументом, коли галузь використовує bash або еквівалентну оболонку в> 99,9% усіх середовищ. Це зводиться до читабельності, і є дві сторони: деякі люди кажуть, що "функція" робить це очевидним, люди, які дізналися її за стандартами posix або іншими оболонками, скажуть, що брекети є більш очевидним стилем. Врешті-решт, виберіть один у своїй групі чи компанії та дотримуйтесь його.
Hubert Grzeskowiak

92

functionКлючове слово було введено в KSH . Традиційна оболонка Борна мала лише foo ()синтаксис, а POSIX стандартизує лише foo ()синтаксис.

У ATT ksh (але не pdksh) є кілька відмінностей між функціями, визначеними functionта функціями, визначеними синтаксисом Bourne / POSIX. У функціях, визначених function, typesetключове слово оголошує локальну змінну: як тільки функція закінчується, значення змінної повертається до того, що було до введення функції. За допомогою класичного синтаксису змінні мають глобальну область застосування, використовуєте ви typesetчи ні.

$ ksh -c 'a=global; f () { typeset a=local; }; f; echo $a'
local
$ ksh -c 'a=global; function f { typeset a=local; }; f; echo $a'
global

Ще одна відмінність ksh полягає в тому, що функції, визначені functionключовим словом, мають власний контекст пастки. Пастки, визначені поза функцією, ігноруються під час виконання функції, а фатальні помилки всередині функції виходять лише з функції, а не з усього сценарію. Також $0є ім'я функції у функції, визначеній, functionале ім'ям сценарію у функції, визначеній за допомогою ().

Pdksh не емулює ATT ksh. У pdksh typesetстворює змінні з локальним діапазоном незалежно від функції, і немає локальних пасток (хоча використання functionцього робить деякі незначні відмінності - детальну інформацію див. На сторінці man).

Bash і zsh представили functionключове слово для сумісності з ksh. Однак у цих оболонок function foo { … }і foo () { … }строго однакові, як і розширення bash і zsh function foo () { … }. typesetКлючове слово завжди оголошує локальні змінні ( за винятком -g, звичайно), і пастки не є локальними (ви можете отримати локальні пастки в Zsh, встановивши local_trapsопцію).


8
Слід зазначити, що підтримка функції була додана до оболонки Korn до того, як оболонка Bourne представила свій foo() commandсинтаксис, а синтаксис Bourne згодом був доданий до оболонки Korn для сумісності.
Стефан Шазелас

2
Чи правильно, що function { ... }; f;не залишається fпісля functionключового слова?
Руслан

32
foo() any-command

Синтаксис Борна підтримується будь-Борн-подібної оболонкою , але bash, yashі останні версії posh(які підтримують тільки складові команди). (оболонка Bourne та реалізація AT&T kshне підтримують, foo() any-command > redirectionsякщо any-commandце не складна команда).

foo() any-compound-command

(Приклади з'єднання команд: { cmd; }, for i do echo "$i"; done, (cmd)... найбільш часто використовуваний істота { ...; })

- це синтаксис POSIX, який підтримується будь-якою оболонкою Bourne, і той, який ти зазвичай хочеш використовувати.

function foo { ...; }

є синтаксисом оболонки Корна, який передує синтаксису Борна. Використовуйте цей лише тоді, коли ви пишете спеціально для AT&T реалізації оболонки Korn і потребуєте конкретного лікування, яке воно там отримує. Цей синтаксис НЕ POSIX, але підтримується bash, yashі zshдля сумісності з оболонкою Korn , хоча ці снаряди (і pdksh-А варіанти Korn оболонки) не застосовуватися до нього не відрізняються від стандартного синтаксису.

function foo () { ...; }

є синтаксисом без оболонки і не повинен використовуватися . Це відбувається тільки за підтримки аварії на bash, yash, zshі на pdkshоснові варіантів оболонки Korn. До речі, це також awkсинтаксис функції.

Якщо ми продовжимо спускатися по езотеричному списку,

function foo() other-compound-command

(як function foo() (subshell)або function foo() for i do; ... done) ще гірше. Вона підтримується bash, yashі zsh, але не КШ, навіть pdksh-На варіанти.

Поки:

function foo() simple command

підтримується лише користувачем zsh.


1
Синтаксис, що включає як functionключове слово, так і круглі дужки, задокументований у Bash. Посібник Bash 4.2 і пізніше говорить, що функції оголошуються синтаксисом name () compound-command [ redirections ]або function name [()] compound-command [ redirections ]. У Bash 4.1.11, щонайменше, до 3.0-бета-версії, це був лише той самий рядок, [ function ] name () compound-command [redirection]який помилково не охоплює синтаксис, що включає functionключове слово, але не круглі дужки, але все ще охоплює синтаксис, що включає як functionключове слово, так і круглі дужки.
нісетама

@nise, справа полягає в тому, що він bashрозпізнає function foo {крім foo() {сумісності з оболонкою Korn (і завжди є), щоб він міг інтерпретувати сценарії, написані для оболонки Korn. Він також підтримує function foo () {, але немає вагомих причин використовувати цю.
Стефан Шазелас

2
@ StéphaneChazelas Ну, я б сказав, що є вагомий привід для використання function f() {. А саме, з точки зору читабельності, це буде визнано функцією будь-хто, хто знає англійську мову, і хтось, хто знає C, порівняно лише з одним із цих наборів.
ДепресіяДаніель

2
Повинна бути прийнята відповідь. Дійсно важливийYou should never combine the keyword function with the parentheses () when defining a function.
4wk_

Ласкаво просимо до 2019 року, де існує лише один галузевий де-факто стандарт для сценаріїв автоматизації linux / unix; один перекладач, який встановлений майже майже скрізь (екзотичні середовища вбік): bash. Напишіть свій код з усіма басовими функціями, використовуйте шебанг, і вам буде добре. Аргумент сумісності недійсний.
Hubert Grzeskowiak

22

Семантично ці дві форми рівнозначні в Баші.

На чоловіковій сторінці:

Функції оболонки декларуються наступним чином:

name () compound-command [redirection]
function name [()] compound-command [redirection]

Це визначає функцію з назвою name. Зарезервоване слово функція НЕ є обов'язковою. Якщо подано функцію зарезервованого слова, дужки не є обов'язковими.

EDIT: Я щойно помітив, що це питання позначено тегами posix. У POSIX sh, то functionключове слово не використовується (хоча він зарезервований).


3

Наразі кілька інших відповіли правильно, але ось мій короткий конспект:

Друга версія є портативною і, ймовірно, працює з багатьма стандартними (особливо POSIX) оболонками.

Перша версія буде працювати лише з bash, але ви можете опустити круглі дужки, слідуючи за ім'ям функції.

В іншому випадку вони представляють однакові сутності після інтерпретації їх bash.


насправді перша версія не має сенсу, крім обмеження її як прийнятного синтаксису деякими оболонками. коли включати () іfunction ключове слово оболонка поводиться так , як ніби ви тільки що зробили в foo(){ ...; }будь-якому випадку, за винятком, звичайно, для оболонки , в якій він є недійсним синтаксис. і так ви повинні робити, function foo { ...; }якщо потрібно чи foo(){ ...; }іншим чином.
mikeserv
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.