Retorno implícito em funções bash?

5

Digamos que eu tenha uma função bash assim:

gmx(){
  echo "foo";
}

essa função implicitamente retornará o valor de saída do comando echo ou estará usando o retorno necessário?

gmx(){
  echo "foo";
  return $?
}

Eu assumo que a forma como o bash funciona, o status de saída do comando final da função bash é aquele que é "retornado", mas não tem 100% de certeza.

    
por Alexander Mills 28.05.2018 / 09:14

4 respostas

7

return faz um explícito retornar de uma função shell ou "script de ponto" (um script originado). Se return não for executado, um retorno implícito será feito no final da função de shell ou script de ponto.

Se return for executado sem um parâmetro, é equivalente a retornar o status de saída do comando executado mais recentemente.

É assim que return funciona em todos os shells do POSIX.

Por exemplo,

gmx () {
  echo 'foo'
  return "$?"
}

é, portanto, equivalente a

gmx () {
  echo 'foo'
  return
}

que é o mesmo que

gmx () {
  echo 'foo'
}

Em geral, é muito raro que você precise usar $? . É realmente necessário apenas se você precisar salvá-lo para uso futuro, por exemplo, se precisar investigar seu valor várias vezes (nesse caso, você atribuirá seu valor a uma variável e executará uma série de testes nessa variável). / p>     

por 28.05.2018 / 10:37
5

Na página bash(1) man:

When executed, the exit status of a function is the exit status of the last command executed in the body.

    
por 28.05.2018 / 09:16
2

Vou apenas adicionar algumas notas de cautela às respostas já fornecidas:

  • Mesmo que return tenha um significado muito especial para o shell, do ponto de vista da sintaxe, ele é um comando interno do shell e uma instrução de retorno é analisada como qualquer outro comando simples. Então, isso significa que, como no argumento de qualquer outro comando, $? quando não citações, estaria sujeito a split + glob

    Então, você precisa citar $? para evitar:

    return "$?"
    
  • return geralmente não aceita nenhuma opção ( ksh93 's aceita o usual --help , --man , --author ... embora). O único argumento esperado (opcional) é o código de retorno. O intervalo de códigos de retorno aceitos varia de shell para shell e se qualquer valor fora de 0..255 é refletido adequadamente em $? também varia de shell para shell. Veja Código de saída padrão quando o processo é encerrado? para detalhes sobre isso.

    A maioria dos shells aceitam números negativos (afinal, o argumento transmitido para a chamada de sistema _exit() / exitgroup() é um int , portanto, com valores abrangendo pelo menos -2 31 a 2 31 -1, então faz sentido que shells aceitem o mesmo intervalo para suas funções).

    A maioria dos shells usa waitpid() e co. API para recuperar esse status de saída, no entanto, nesse caso, ele será truncado para um número entre 0 e 255 quando armazenado em $? . Mesmo que a invocação de uma função não envolva a geração de um processo e use waitpid() para recuperar seu status de saída, já que tudo é feito no mesmo processo, muitos shells também imitam esse comportamento waitpid() ao invocar funções. O que significa que mesmo se você chamar return com um valor negativo, $? conterá um número positivo.

    Agora, entre aqueles shells cujo return aceita números negativos (ksh88, ksh93, bash, zsh, pdksh e derivados diferentes de mksh, yash), existem alguns (pdksh e yash) que precisam ser escritos como return -- -123 caso contrário, -123 é considerado como três -1 , -2 , -3 opções inválidas.

    Como pdksh e seus derivados (como OpenBSD sh ou posh ) preservam o número negativo em $? , isso significa que fazer return "$?" falharia quando $? continha um número negativo (o que aconteceria quando o último comando de execução foi uma função que retornou um número negativo).

    Então return -- "$?" seria melhor nessas conchas. No entanto, observe que, embora seja suportado pela maioria dos shells, essa sintaxe não é POSIX e, na prática, não é suportada por mksh e derivados de cinza.

    Então, para resumir, com shells baseados em pdksh, você pode usar números negativos em argumentos para funções, mas se você fizer isso, return "$@" não funcionará. Em outros shells, return "$@" funcionará e você deve evitar usar números negativos (ou números fora de 0..255) como argumentos para return .

  • Em todos os shells que eu conheço, chamar return de dentro de um subshell sendo executado dentro de uma função fará com que o subshell saia (com o status de saída fornecido se algum ou aquele do último comando for executado), mas não causará um retorno da função (para mim, não está claro se o POSIX dá a você essa garantia, alguns argumentam que exit deve ser usado em vez de subconsultas de saída dentro de funções). Por exemplo

    f() {
      (return 3)
      echo "still inside f. Exit status: $?"
    }
    f
    echo "f exit status: $?"
    

    produzirá:

    still inside f. Exit status: 3
    f exit status: 0
    
por 28.05.2018 / 20:00
0

Sim, o valor de retorno implícito de uma função é o status de saída do último comando executado . Isso também é verdade em qualquer ponto de qualquer script de shell. Em qualquer ponto da sequência de execução do script, o status de saída atual é o status de saída do último comando executado. Mesmo comando executado como parte de uma atribuição de variável: var=$(exit 34) . A diferença com as funções é que uma função pode alterar o status de saída no final da execução da função.

A maneira alternativa de alterar o "status de saída atual" é iniciar um subconjunto e sair dele com qualquer status de saída necessário:

$ $(exit 34)
$ echo "$?"
34

E sim, o status de saída expansão precisa ser citado:

$ IFS='123'
$ $(exit 34)
$ echo $?
4

Um (exit 34) também funciona.
Alguns podem argumentar que uma construção mais robusta deve ser $(return 34) e que uma saída deve "sair" do script que está sendo executado. Mas $(return 34) não funciona com qualquer versão do bash. Então, não é portátil.

A maneira mais segura de definir um status de saída é usá-lo como foi projetado para funcionar, definir e return de uma função:

exitstatus(){ return "${1:-"$?"}"; }

Então, no final de uma função. é exatamente equivalente a não ter nada ou return ou return "$?" . O final de uma função não precisa significar a "última linha de código de uma função".

#!/bin/sh
exitstatus(){ a="${1:-"$?"}"; return "$a"; }
gmx(){
    if     [ "$1" = "one" ]; then
           printf 'foo ';
           exitstatus 78
           return "$?"
    elif   [ "$1" = "two" ]; then
           printf 'baz ';
           exitstatus 89
           return
    else
           printf 'baz ';
           exitstatus 90
    fi
}  

imprimirá:

$ ./script
foo 78
baz 89
baz 90

O único uso prático para "$?" é imprimir seu valor: echo "$?" ou armazená-lo em uma variável (como é um valor efêmero e mudar com cada comando executado): exitstatus=$? (lembre-se de citar a variável em comandos como export EXITSTATUS="$?" .

No comando return , o intervalo válido de valores é geralmente de 0 a 255, mas entenda que valores de 126 + n são usados por alguns shells para sinalizar status de saída especial, portanto, a recomendação geral é usar 0- 125.

    
por 29.05.2018 / 06:28