differenza tra "function foo () {}" e "foo () {}"


98

Posso definire le bashfunzioni usando o omettendo la functionparola chiave. C'è qualche differenza?

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar

Le chiamate per le funzioni fooe baravere successo e non riesco a vedere alcuna differenza. Quindi mi chiedo se è solo per migliorare la leggibilità, o c'è qualcosa che mi manca ...

A proposito in altre shell come dash( /bin/shè simbolicamente collegato a dashdebian / ubuntu) non riesce quando si utilizza la functionparola chiave.


8
Inoltre, con o senza la parentesi: function baz { echo "baz"; }. Vedi Bashism nella wiki di GreyCat.
arte

Risposte:


43

AFAIK non fa differenza, a parte il fatto che la seconda versione è più portatile.


32
Questa è una GRANDE differenza, portabilità ... Vedo troppe risposte che semplicemente NON funzionano su (vecchi) sistemi di produzione, e anche molte con opzioni che funzionano solo su Linux. Almeno, avvisa che questo non è il modo più portatile ... Potrebbe essere assolutamente pericoloso (chiedere a qualcuno di farlo tar cf - /some/thing | ssh user@desthost "cd destinationdir && tar xf - " senza avvertirlo di controllare prima se la versione di tar su destSost si libererà del "/" potrebbe portare a disastri in alcuni casi ...). Per esempio: se usi a function tar { #a safe tar with safety checks ... }e lo shignori, ...
Olivier Dulac il

1
@OlivierDulac Aggiungerei che gli script che assumono shriconoscono la functionparola chiave - e, in generale, che assumono funzionalità comuni ma non standard che le shell gradiscono kshe bashoffrono - spesso non funzioneranno su sistemi di produzione più recenti , anche se funzionavano su versioni precedenti di lo stesso sistema operativo. bashfornisce ancora shsu molti sistemi GNU / Linux, ma alcune distro popolari sono passate ad avere shun link simbolico a dash(Debian Almquist SHell) per migliorare le prestazioni. Questo include Debian e Ubuntu .
Eliah Kagan,

2
Senza elaborare come sia "più portatile", la risposta non è utile.
ivan_pozdeev il

La portabilità non è un argomento al giorno d'oggi in cui l'industria utilizza bash o una shell equivalente in> 99,9% di tutti gli ambienti. Si riduce alla leggibilità e ci sono due lati: alcune persone dicono che la "funzione" lo rende ovvio, le persone che l'hanno imparato dagli standard posix o altre conchiglie diranno che le parentesi graffe sono lo stile più ovvio. Alla fine, sceglierne uno all'interno del tuo gruppo o azienda e attenersi ad esso.
Hubert Grzeskowiak,

95

La functionparola chiave è stata introdotta in ksh . La shell Bourne tradizionale aveva solo la foo ()sintassi e POSIX standardizza solo la foo ()sintassi.

In ATT ksh (ma non in pdksh), ci sono alcune differenze tra le funzioni definite da functione quelle definite con la sintassi Bourne / POSIX. Nelle funzioni definite da function, la typesetparola chiave dichiara una variabile locale: una volta terminata la funzione, il valore della variabile viene riportato a quello che era prima di entrare nella funzione. Con la sintassi classica, le variabili hanno un ambito globale sia che si usi typeseto meno.

$ 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

Un'altra differenza in ksh è che le funzioni definite con la functionparola chiave hanno il proprio contesto trap. Le trap definite all'esterno della funzione vengono ignorate durante l'esecuzione della funzione e gli errori fatali all'interno della funzione escono solo dalla funzione e non dall'intero script. Inoltre, $0è il nome della funzione in una funzione definita da functionma il nome dello script in una funzione definita con ().

Pdksh non emula ATT ksh. In pdksh, typesetcrea variabili con ambito locale indipendentemente dalla funzione e non ci sono trap locali (sebbene l'uso functionfaccia alcune differenze minori - vedi la pagina man per i dettagli).

Bash e zsh hanno introdotto la functionparola chiave per la compatibilità con ksh. Tuttavia in queste shell function foo { … }e foo () { … }sono strettamente identici, così come l'estensione bash e zsh function foo () { … }. La typesetparola chiave dichiara sempre le variabili locali (tranne -govviamente con) e le trap non sono locali (è possibile ottenere trap locali in zsh impostando l' local_trapsopzione).


8
Va notato che il supporto delle funzioni è stato aggiunto alla shell Korn prima che la shell Bourne introducesse la sua foo() commandsintassi, e la sintassi Bourne è stata successivamente aggiunta alla shell Korn per compatibilità.
Stéphane Chazelas,

2
È corretto che function { ... }; f;omette fla functionparola chiave?
Ruslan,

32
foo() any-command

è la sintassi Bourne supportato da qualsiasi shell Bourne simile ma bash, yashe versioni più recenti di posh(che supportano solo comandi composti). (la shell Bourne e le implementazioni AT&T di kshnon supportano a foo() any-command > redirectionsmeno che non any-commandsia un comando composto però).

foo() any-compound-command

(esempi di composti comandi: { cmd; }, for i do echo "$i"; done, (cmd)... l'essere più comunemente utilizzati { ...; })

è la sintassi POSIX supportata da qualsiasi shell tipo Bourne e quella che generalmente si desidera utilizzare.

function foo { ...; }

è la sintassi della shell Korn, che precede la sintassi di Bourne. Usa questo solo se scrivi specificatamente per l'implementazione AT&T della shell Korn e hai bisogno del trattamento specifico che riceve lì. Questa sintassi non è POSIX, ma è supportata da bash, yashe zshper compatibilità con la shell Korn sebbene quelle shell (e le pdkshvarianti basate sulla shell Korn) non la trattino in modo diverso dalla sintassi standard.

function foo () { ...; }

è la sintassi di nessuna shell e non deve essere utilizzata . Succede solo per essere sostenuto da incidente da bash, yash, zshe le pdkshvarianti base del Korn. Per inciso, è anche la awksintassi della funzione.

Se continuiamo a scendere l'elenco esoterico,

function foo() other-compound-command

(come function foo() (subshell)o function foo() for i do; ... done) è anche peggio. È supportato da bash, yashe zsh, ma non da ksh, anche dalle pdkshvarianti basate su.

Mentre:

function foo() simple command

è supportato solo da zsh.


1
La sintassi che include sia la functionparola chiave che le parentesi è documentata in Bash. Il manuale di Bash 4.2 e versioni successive afferma che le funzioni sono dichiarate dalla sintassi name () compound-command [ redirections ]o function name [()] compound-command [ redirections ]. In Bash 4.1.11 fino almeno alla 3.0-beta quella era solo la singola riga [ function ] name () compound-command [redirection]che erroneamente non copre la sintassi che include la functionparola chiave ma non le parentesi ma copre ancora la sintassi che include sia la functionparola chiave che le parentesi.
nisetama,

@nise, il punto è che bashriconosce function foo {oltre alla foo() {compatibilità con la shell Korn (e lo ha sempre fatto) in modo che possa interpretare gli script scritti per la shell Korn. Supporta function foo () {anche, ma non c'è una buona ragione per usarlo.
Stéphane Chazelas,

2
@ StéphaneChazelas Bene, direi che c'è un buon motivo per usarlo function f() {. Vale a dire, in termini di leggibilità, verrà riconosciuta come una funzione da chiunque conosca l'inglese e chiunque conosca C, rispetto a uno solo di questi set.
Depresso

2
Dovrebbe essere la risposta accettata. Davvero importanteYou should never combine the keyword function with the parentheses () when defining a function.
4wk_

Benvenuti nel 2019, dove esiste solo uno standard di fatto del settore per gli script di automazione linux / unix; l'unico interprete installato praticamente quasi ovunque (ambienti esotici a parte): bash. Scrivi il tuo codice con tutte le funzionalità di bash, usa shebang e andrà tutto bene. L'argomento della compatibilità è nullo.
Hubert Grzeskowiak, il

22

Semanticamente, queste due forme sono equivalenti in Bash.

Dalla pagina man:

Le funzioni della shell sono dichiarate come segue:

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

Questo definisce una funzione denominata name. La funzione di parola riservata è facoltativa. Se viene fornita la parola riservata alla funzione , le parentesi sono opzionali.

EDIT: ho appena notato che questa domanda è taggata posix. In POSIX sh, la functionparola chiave non viene utilizzata (sebbene sia riservata).


3

Ormai molti altri hanno risposto correttamente, ma ecco la mia concisa sinossi:

La seconda versione è portatile ed è probabile che funzioni con molte shell standard (in particolare POSIX).

La prima versione funzionerà solo con bash, ma è possibile omettere le parentesi che seguono il nome della funzione.

Altrimenti, rappresentano entità identiche dopo che bash le interpreta.


in realtà, la prima versione non ha senso se non per limitarla come sintassi accettabile ad alcune shell. quando includi la () e la functionparola chiave la shell si comporta come se lo avessi fatto foo(){ ...; }comunque, tranne, ovviamente, per una shell in cui è sintassi non valida. e quindi dovresti fare function foo { ...; }se devi, o foo(){ ...; }altrimenti.
Mikeserv,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.