diferença entre "função foo() {}" e "foo() {}"

diferença entre "função foo() {}" e "foo() {}"

Posso definir bashfunções usando ou omitindo a functionpalavra-chave. Existe alguma diferença?

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar

Ambas as chamadas para funções foosão barbem-sucedidas e não consigo ver nenhuma diferença. Então, estou me perguntando se é apenas para melhorar a legibilidade ou se há algo que estou faltando ...

BTW em outros shells como dash( /bin/shtem link simbólico dashno debian/ubuntu) ele falha ao usar a functionpalavra-chave.

Responder1

A razão pela qual existem duas sintaxes diferentes é histórica. A functionpalavra-chave veio deksh. A sintaxe inspirada em C ()veio doConcha Bourne.POSIXpadroniza apenas a foo ()sintaxe Bourne. Bash e zsh suportam ambos, assim como o hybrid function foo () { … }. Exceto no ATT ksh, a função resultante é exatamente a mesma.

Cuidado com uma pegadinha com a ()sintaxe: o nome da função está sujeito à expansão do alias.

alias f=g
f () { echo foo; }
type f               # f is an alias for g
type g               # g is a shell function
f                    # alias f → function g → print foo
\f                   # no alias lookup → f: not found
g                    # function g

No ATT ksh (mas não no pdksh e seus descendentes, como mksh), existem algumas diferenças entre funções definidas por functione funções definidas com a sintaxe Bourne/POSIX. Nas funções definidas por function, a typesetpalavra-chave declara uma variável local: assim que a função termina, o valor da variável é redefinido para o que era antes de entrar na função. Com a sintaxe clássica, as variáveis ​​têm um escopo global, quer você use typesetou não.

$ 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

Outra diferença no ksh é que as funções definidas com a functionpalavra-chave possuem seu próprio contexto de trap. As armadilhas definidas fora da função são ignoradas durante a execução da função, e erros fatais dentro da função saem apenas da função e não de todo o script. Além disso, $0o nome da função em uma função é definido por, functionmas o nome do script em uma função é definido com ().

Pdksh não emula ATT ksh. No pdksh, typesetcria variáveis ​​com escopo local, independentemente da função, e não há armadilhas locais (embora o uso functionfaça algumas pequenas diferenças - consulte a página de manual para obter detalhes).

Bash e zsh introduziram a functionpalavra-chave para compatibilidade com ksh. No entanto, nesses shells function foo { … }e foo () { … }são estritamente idênticos, assim como as extensões bash e zsh function foo () { … }(exceto para potencial expansão de alias ao analisar a definição, conforme explicado acima). A typesetpalavra-chave sempre declara variáveis ​​locais (exceto com, -gé claro), e as armadilhas não são locais (você pode obter armadilhas locais no zsh definindo a local_trapsopção).

Responder2

Não há diferença no AFAIK, a não ser o fato da segunda versão ser mais portátil.

Responder3

foo() any-command

é a sintaxe Bourne suportada por qualquer shell do tipo Bourne, mas bash,yashe versões recentes de posh(que suportam apenas comandos compostos). (o Bourne Shell e as implementações da AT&T kshnão suportam, foo() any-command > redirectionsa menos que any-commandseja um comando composto).

foo() any-compound-command

(exemplos de comandos compostos: { cmd; }, for i do echo "$i"; done, (cmd)... sendo o mais comumente usado { ...; })

é a sintaxe POSIX suportada por qualquer shell do tipo Bourne e aquela que você geralmente deseja usar.

function foo { ...; }

é a sintaxe do shell Korn, que antecede a sintaxe Bourne. Use este apenas se estiver escrevendo especificamente para a implementação da AT&T do shell Korn e precisar do tratamento específico que recebe lá. Essa sintaxe não é POSIX, mas é suportada por bashe para compatibilidade com o shell Korn, embora esses shells (e as yashvariantes baseadas em -do shell Korn) não a tratem de maneira diferente da sintaxe padrão.zshpdksh

function foo () { ...; }

é a sintaxe denãocasca enão deve ser usado. Acontece que ele só é suportado acidentalmente por bash, e pelas variantes baseadas no shell Korn. Aliás, é também a sintaxe da função.yashzshpdkshawk

Se continuarmos descendo na lista esotérica,

function foo() other-compound-command

(como function foo() (subshell)ou function foo() for i do; ... done) é ainda pior. É suportado por bash, yashe zsh, mas não por ksh, mesmo pelas pdkshvariantes baseadas em -.

Enquanto:

function foo() simple command

só é suportado por zsh.

foo bar() any-command

Ou ainda:

$function_list() any-command

Definir várias funções ao mesmo tempo só é suportado porzsh

function { body; } args
() any-compound-command args

Que sãofunção anônimainvocações, são suportadas apenas por zshtambém.

Responder4

Vários outros já responderam corretamente, mas aqui está minha sinopse concisa:

A segunda versão é portátil e provavelmente funcionará com muitos shells padrão (particularmente POSIX).

A primeira versão funcionará apenas com bash, mas você pode omitir os parênteses após o nome da função.

Caso contrário, eles representam entidades idênticas após o bash interpretá-los.

informação relacionada