różnica między „function foo () {}” a „foo () {}”

96

Potrafię zdefiniować bashfunkcje za pomocą lub pominięcia functionsłowa kluczowego. Czy jest jakaś różnica?

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar

Oba wywołania funkcji fooi barodnieść sukces i nie widzę żadnej różnicy. Zastanawiam się więc, czy chodzi tylko o poprawę czytelności, czy czegoś mi brakuje ...

BTW w innych powłokach, takich jak dash( /bin/shjest dowiązaniem symbolicznym do dashdebian / ubuntu), nie działa przy użyciu functionsłowa kluczowego.

Carlos Campderrós
źródło
8
Także z lub bez nawiasów: function baz { echo "baz"; }. Zobacz bashowymi w wiki GreyCat użytkownika.
manatwork

Odpowiedzi:

42

Nie ma różnicy AFAIK, poza tym, że druga wersja jest bardziej przenośna.

schaiba
źródło
32
To DUŻA różnica, przenośność ... Widzę zbyt wiele odpowiedzi, które po prostu NIE działają na (starszych) systemach produkcyjnych, a także wiele z opcjami, które działają tylko na systemie Linux. Przynajmniej ostrzeż, że nie jest to najbardziej przenośny sposób ... Może być wręcz niebezpieczny (proszenie kogoś, aby tar cf - /some/thing | ssh user@desthost "cd destinationdir && tar xf - " bez uprzedniego ostrzeżenia najpierw sprawdził, czy wersja tar na desthostu pozbędzie się „/” może prowadzić do katastrofy w niektórych przypadkach ...). Na przykład: jeśli używasz a function tar { #a safe tar with safety checks ... }i shignoruje to, ...
Olivier Dulac
1
@OlivierDulac Dodałbym, że skrypty, które zakładają shrozpoznają functionsłowo kluczowe - i, ogólnie rzecz biorąc, które przyjmują wspólne, ale niestandardowe funkcje, które powłoki lubią kshi bashoferują - również często nie będą działać na nowszych systemach produkcyjnych, nawet jeśli działały na starszych wydaniach ten sam system operacyjny. bashwciąż działa shna wielu systemach GNU / Linux, ale niektóre popularne dystrybucje przeszły na posiadanie shjako dowiązanie symboliczne do dash(Debell Almquist SHell) w celu poprawy wydajności. Obejmuje to Debian i Ubuntu .
Eliah Kagan
2
Bez wyjaśnienia, w jaki sposób jest „bardziej przenośny”, odpowiedź nie jest przydatna.
ivan_pozdeev
Przenośność nie jest obecnie argumentem, gdy branża używa bash lub równoważnej powłoki w> 99,9% wszystkich środowisk. Sprowadza się do czytelności i są dwie strony: niektórzy mówią, że „funkcja” czyni to oczywistym, ludzie, którzy nauczyli się tego ze standardów posix lub innych powłok, powiedzą, że nawiasy klamrowe są bardziej oczywistym stylem. Na koniec wybierz jedną ze swojej grupy lub firmy i trzymaj się jej.
Hubert Grzeskowiak
92

functionHasło zostało wprowadzone w ksh . Tradycyjna powłoka Bourne'a miała tylko foo ()składnię, a POSIX standaryzuje tylko foo ()składnię.

W ATT ksh (ale nie pdksh) istnieje kilka różnic między funkcjami zdefiniowanymi przez functioni funkcjami zdefiniowanymi za pomocą składni Bourne / POSIX. W funkcjach zdefiniowanych przez functionThe typesetkluczowe deklaruje zmienną lokalną: raz wyjść funkcyjnych, wartość zmiennej jest ustawiany na to, co było przed wejściem do funkcji. Przy klasycznej składni zmienne mają zasięg globalny, niezależnie od tego, czy korzystasz, typesetczy nie.

$ 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

Inną różnicą w ksh jest to, że funkcje zdefiniowane za pomocą functionsłowa kluczowego mają własny kontekst pułapki. Pułapki zdefiniowane poza funkcją są ignorowane podczas wykonywania funkcji, a krytyczne błędy wewnątrz funkcji wychodzą tylko z funkcji, a nie z całego skryptu. Ponadto, $0nazwa funkcji w funkcji jest zdefiniowana przez, functionale nazwa skryptu w funkcji zdefiniowanej przez ().

Pdksh nie emuluje ksh ATT. W pdksh typesettworzy zmienne o zasięgu lokalnym, niezależnie od funkcji, i nie ma pułapek lokalnych (chociaż użycie functionpowoduje niewielkie różnice - zobacz stronę manuala, aby uzyskać szczegółowe informacje).

Bash i zsh wprowadzili functionsłowo kluczowe dla zgodności z ksh. Jednak w tych pocisków function foo { … }i foo () { … }są absolutnie identyczne, jak to bash i zsh rozszerzenie function foo () { … }. Słowo typesetkluczowe zawsze deklaruje zmienne lokalne (z wyjątkiem -goczywiście), a pułapki nie są lokalne (można uzyskać pułapki lokalne w zsh, ustawiając local_trapsopcję).

Gilles
źródło
8
Należy zauważyć, że obsługa funkcji została dodana do powłoki Korn, zanim powłoka Bourne wprowadziła swoją foo() commandskładnię, a składnia Bourne została później dodana do powłoki Korn w celu zachowania zgodności.
Stéphane Chazelas
2
Czy to prawda, że function { ... }; f;pomija fpo functionhasła?
Ruslan
32
foo() any-command

to składnia Bourne'a obsługiwana przez dowolną powłokę podobną do Bourne'a bash, yasha także najnowsze wersje posh(które obsługują tylko polecenia złożone). (implementacje powłoki Bourne'a i AT&T kshnie obsługują, foo() any-command > redirectionschyba że any-commandjest to polecenie złożone).

foo() any-compound-command

(Przykłady związku Polecenia: { cmd; }, for i do echo "$i"; done, (cmd)... najczęściej są stosowane w { ...; })

to składnia POSIX obsługiwana przez dowolną powłokę podobną do Bourne'a i ta, której ogólnie chcesz używać.

function foo { ...; }

to składnia powłoki Korna, która poprzedza składnię Bourne'a. Używaj go tylko wtedy, gdy piszesz specjalnie dla implementacji AT&T powłoki Korn i potrzebujesz specjalnego traktowania, które tam otrzyma. Że składnia POSIX nie jest, ale jest wspierany przez bash, yashi zshdla kompatybilności z powłoki Korna chociaż te muszle (oraz pdkshopartych warianty Korn shell) nie traktować go różni od standardowej składni.

function foo () { ...; }

jest składnią braku powłoki i nie należy jej używać . To tylko dzieje się przez przypadek wspierane przez bash, yash, zsha pdkshwariantach opartych na powłoce Korna. Nawiasem mówiąc, jest to również awkskładnia funkcji.

Jeśli będziemy nadal schodzić po liście ezoterycznej,

function foo() other-compound-command

(jak function foo() (subshell)lub function foo() for i do; ... done) jest jeszcze gorszy. Jest obsługiwany przez bash, yashi zsh, ale nie ksh, nawet pdkshoparte na wariantach.

Podczas:

function foo() simple command

jest obsługiwany tylko przez zsh.

Stéphane Chazelas
źródło
1
Składnia, która zawiera zarówno functionsłowo kluczowe, jak i nawiasy, jest udokumentowana w języku Bash. Podręcznik Bash 4.2 i późniejszych mówi, że funkcje są deklarowane przez składnię name () compound-command [ redirections ]lub function name [()] compound-command [ redirections ]. W wersji Bash 4.1.11 do co najmniej 3.0-beta była to tylko pojedyncza linia, [ function ] name () compound-command [redirection]która błędnie nie obejmuje składni zawierającej functionsłowo kluczowe, ale nie zawiera nawiasów, ale nadal obejmuje składnię zawierającą zarówno functionsłowo kluczowe, jak i nawiasy.
nisetama
@nise, chodzi o to, że bashrozpoznaje function foo {oprócz foo() {kompatybilności z powłoką Korna (i zawsze ma), dzięki czemu może interpretować skrypty napisane dla powłoki Korna. Obsługuje function foo () {również, ale nie ma dobrego powodu, aby z niego korzystać.
Stéphane Chazelas,
2
@ StéphaneChazelas Cóż, powiedziałbym, że jest dobry powód do korzystania function f() {. Mianowicie, pod względem czytelności, będzie rozpoznawany jako funkcja przez każdego, kto zna angielski i każdego, kto zna C, w porównaniu z tylko jednym z tych zestawów.
Depressed
2
Powinna być zaakceptowana odpowiedź. Naprawdę ważneYou should never combine the keyword function with the parentheses () when defining a function.
tyk
Witamy w 2019 roku, w którym istnieje tylko jeden faktyczny standard branżowy dla skryptów automatyzacji linux / unix; jedyny interpreter, który jest zainstalowany prawie wszędzie (poza egzotycznymi środowiskami): bash. Napisz kod ze wszystkimi funkcjami bash, użyj shebang, a wszystko będzie dobrze. Argument zgodności jest nieważny.
Hubert Grzeskowiak
22

Semantycznie te dwie formy są równoważne w Bash.

Ze strony podręcznika:

Funkcje powłoki są deklarowane w następujący sposób:

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

Definiuje funkcję o nazwie name. Zastrzeżony słowo funkcja jest opcjonalna. Jeśli podano słowo zarezerwowane dla funkcji , nawiasy są opcjonalne.

EDYCJA: Właśnie zauważyłem, że to pytanie jest oznaczone posix. W POSIX shThe functionsłowo kluczowe nie jest używana (choć jest on zarezerwowany).

depquid
źródło
3

Do tej pory kilka innych osób odpowiedziało poprawnie, ale oto moje zwięzłe streszczenie:

Druga wersja jest przenośna i prawdopodobnie będzie działać z wieloma standardowymi powłokami (szczególnie POSIX).

Pierwsza wersja będzie działać tylko z bash, ale możesz pominąć nawiasy następujące po nazwie funkcji.

W przeciwnym razie reprezentują identyczne byty po ich interpretacji przez bash.

destenson
źródło
w rzeczywistości pierwsza wersja nie ma sensu, poza ograniczeniem jej jako akceptowalnej składni do niektórych powłok. Jeśli użytkownik włączy () ifunction kluczowe powłoka zachowuje się tak, jakby po prostu nie foo(){ ...; }tak, z wyjątkiem, oczywiście, do muszli, w której jest nieprawidłowa składnia. i dlatego powinieneś to zrobić, function foo { ...; }jeśli musisz lub foo(){ ...; }inaczej.
mikeserv