Qual é o uso de parênteses '()' na definição da função shell?

20

Uma função é definida como:

do_something () {
    do it
}

Eu poderia entender o nome 'do_something' e o colchete para encapsular o código de ações, mas não consigo entender a finalidade do () aqui, pois não há parâmetros nomeados nos scripts Bash. Pode ser melhor e simples defini-lo como

do_something {
  do it
}

O que não está em conflito com a sua sintaxe atual, e ainda mais declara que não há parâmetros nomeados. Qual é o uso de () aqui?

    
por JawSaw 11.04.2018 / 10:23

3 respostas

42

Sem o () , a sintaxe seria realmente ambígua.

Tem de existir alguma sintaxe não ambígua para definir uma função, e sem alterar substancialmente outra sintaxe da shell, não pode ser isto:

do_something {
    # one or more commands go here
}

Você disse que isso "não se confunde com sua sintaxe atual", mas sim! Observe que você não recebe nenhum tipo de erro de sintaxe quando tenta executar a primeira linha desse . Você recebe um erro, mas não é um erro sobre a sintaxe. A segunda linha, com } , é um erro de sintaxe, mas a primeira linha não é. Em vez disso, do_something { tenta executar um comando chamado do_something e passar { como um argumento para esse comando:

$ do_something {
do_something: command not found

Se já houver um comando chamado do_something , você o está executando. Se já existe uma função chamada do_something , você está chamando . É importante, em geral, que a sintaxe não seja ambígua, mas também é importante especificamente que seja possível redefinir uma função sem chamá-la acidentalmente. Definir uma função e chamá-la não deve ser o mesmo.

Como o shell trata { e ( .

Como type { dirá, { é uma palavra-chave do shell. Isso faz com que pareça [[ . Se usado em uma situação em que, de outra forma, seria um comando, { carrega uma semântica especial. Especificamente, ele executa o agrupamento de comandos. Em outras situações, no entanto, ele pode ser usado sem escape para denotar um caractere literal { . Isso inclui a situação de passá-lo como segunda ou subseqüente palavra de um comando.

É claro que o Bash poderia ter sido projetado para tratar { de maneira diferente do que atualmente. No entanto, sua sintaxe não seria mais compatível com o shell POSIX, e o Bash não seria realmente um shell estilo Bourne e não seria capaz de executar muitos scripts de shell.

Por outro lado, ( é um metacaractere de casca. Ele sempre é tratado especialmente se for exibido em um comando e não estiver entre aspas (com ' ' , " " ou \ ). Não há, portanto, ambigüidade na sintaxe:

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

Isso não poderia significar mais nada. Se o Bash não tivesse funções, então seria um erro de sintaxe, pelo mesmo motivo echo foo(bar) é um erro de sintaxe.

Se você realmente não gosta da notação () , então você pode usar a palavra-chave function e omiti-la, como sudodus menciona . Note que esta não é uma parte da sintaxe para definir funções na maioria das outras shells no estilo Bourne - e em algumas, ela é suportada, mas funções definidas dessa maneira têm semântica diferente - e assim um script que a usa não será portátil. (O motivo pelo qual essa sintaxe é capaz de ser inequívoca é que function é em si uma palavra-chave no Bash que significa que o que segue é o início de uma definição de função.)

Finalmente, observe que, embora a maioria das definições de funções use { na prática, qualquer comando composto é permitido. Se você tivesse uma função cujo corpo desejasse sempre executar em uma subcamada, poderia usar ( ) em vez de { } .

    
por Eliah Kagan 11.04.2018 / 10:40
15

O token () é informar ao interpretador de shell que você está declarando uma função.

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

Uma alternativa em bash é function

function do_something {
 echo 'do it'
}

ou como um one-liner você pode testar

$ bash -c "function do_something { echo 'do it'; } ; do_something"
do it
    
por sudodus 11.04.2018 / 10:38
9

Quanta estilo de chave verdadeira - você!

Considere outros estilos de chaves perfeitas:

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

Como o shell pode dizer que essas são definições de funções e não simplesmente um comando foo seguido por listas de comandos? Em todos esses casos, é necessário um fator de eliminação de ambiguidade adicional, como () ou a palavra-chave function .

    
por muru 11.04.2018 / 10:53