Diferença entre retorno e saída nas funções do Bash

429

Qual é a diferença entre a instrução returne exitnas funções do Bash em relação aos códigos de saída?

lecodesportif
fonte
55
Protip: digite help <command>seu shell para obter informações sobre o que um shell incorporado fará. No seu caso help returnehelp exit
SiegeX 12/12/10

Respostas:

318

A partir man bashde return [n];

Faz com que uma função pare de executar e retorne o valor especificado por n ao seu chamador. Se n for omitido, o status de retorno é o do último comando executado no corpo da função.

... em exit [n]:

Faça com que o shell saia com o status n. Se n for omitido, o status de saída é o do último comando executado. Uma interceptação em EXIT é executada antes que o shell termine.

EDITAR:

Conforme sua edição da pergunta, em relação aos códigos de saída, returnnada tem a ver com códigos de saída. Os códigos de saída destinam-se a aplicativos / scripts , não a funções. Portanto, a este respeito, a única palavra-chave que define o código de saída do script (aquele que pode ser capturado pelo programa de chamada usando a $?variável shell) é exit.

EDIT 2:

Minha última declaração referente exitestá causando alguns comentários. Foi feito para diferenciar returne exitpara o entendimento do OP e, de fato, em qualquer ponto determinado de um script de programa / shell, exité a única maneira de finalizar o script com um código de saída para o processo de chamada.

Cada comando executado no shell produz um local "código de saída": ele define a $?variável para que o código, e pode ser usado com if, &&e outros operadores para condicionalmente executar outros comandos.

Esses códigos de saída (e o valor da $?variável) são redefinidos a cada execução de comando.

Aliás, o código de saída do último comando executado pelo script é usado como o código de saída do próprio script, conforme visto pelo processo de chamada.

Finalmente, as funções, quando chamadas, agem como comandos do shell em relação aos códigos de saída. O código de saída da função ( dentro da função) é definido usando return. Portanto, quando uma função return 0é executada, a execução da função termina, fornecendo um código de saída 0.

Diego Sevilla
fonte
10
Não exatamente. Ele sempre retorna um valor do shell atual. Não importa se você está dentro de uma função ou não.
Diego Sevilla
10
Comente sua edição: posso estar confundindo valores de retorno e códigos de saída, mas func(){ return 50; };func;echo $?ecoa 50. Portanto, a $?variável shell não parece estar limitada a exit.
lecodesportif 12/12
8
" $?Expande para o status de saída do pipeline de primeiro plano executado mais recentemente." Essa saída pode ser do shell na forma de uma chamada para exit(ou chegar ao final do script) ou na forma de uma chamada para returndentro de uma função.
SiegeX
11
@lecodesportif: O $? processo / script atual é limitado exitao resultado do último comando executado por este script ou ao resultado. Portanto, se sua última linha de script é a chamada para essa função e essa função retorna 50, sim, a $?que você produz para o processo que chamou você é 50. No entanto, isso não tem a ver com o returnporque é restrito ao script atual. Só será retornado se essa chamada de função for a última frase do script. exit, no entanto, sempre termine o script e retorne esse valor $? ao processo de chamada .
Diego Sevilla
11
-1 por me confundir com a linha " returnnão tem nada a ver com códigos de saída". A experiência me diz que não há diferença funcional entre o código de retorno de uma função e o código de saída de um script.
23415 Jack
296

returnfará com que a função atual fique fora do escopo, enquanto exitfará com que o script termine no ponto em que é chamado. Aqui está um exemplo de programa para ajudar a explicar isso:

#!/bin/bash

retfunc()
{
    echo "this is retfunc()"
    return 1
}

exitfunc()
{
    echo "this is exitfunc()"
    exit 1
}

retfunc
echo "We are still here"
exitfunc
echo "We will never see this"

Resultado

$ ./test.sh
this is retfunc()
We are still here
this is exitfunc()
SiegeX
fonte
17
Belo exemplo. Você também pode mostrar o valor de saída de 1 pol $?.
Diego Sevilla
48
Observe que essa função NÃO imprimirá "Ainda estamos aqui" se você adicionar "set -e" antes da chamada para "retfunc".
Michael
4
No entanto, echo fnord | while read x; do exitfunc; done; echo "still here"imprimirá "ainda aqui". Parece que apenas o whilesub-shell é encerrado neste cenário.
Tripleee
Uma solução aproximada é, done || exit $?porém, feia e não exatamente equivalente.
Tripleee
2
+1 Pode ser útil adicionar: `` ` returnfará com que a função atual ou o script de origem fiquem fora do escopo```.
Isaac
56

Não acho que alguém tenha realmente respondido totalmente à pergunta porque não descreve como os dois são usados. OK, acho que sabemos que exit mata o script, onde quer que seja chamado e você pode atribuir um status a ele, como sair ou sair 0 ou sair 7 e assim por diante. Isso pode ser usado para determinar como o script foi forçado a parar se chamado por outro script, etc. Chega na saída.

return quando chamado retornará o valor especificado para indicar o comportamento da função, geralmente 1 ou 0. Por exemplo:

    #!/bin/bash
    isdirectory() {
      if [ -d "$1" ]
      then
        return 0
      else
        return 1
      fi
    echo "you will not see anything after the return like this text"
    }

verifique assim:

    if isdirectory $1; then echo "is directory"; else echo "not a directory"; fi

ou assim:

    isdirectory || echo "not a directory"

Neste exemplo, o teste pode ser usado para indicar se o diretório foi encontrado. observe que nada após o retorno não será executado na função. 0 é verdadeiro, mas falso é 1 no shell, diferente de outros programas.

Para obter mais informações sobre funções: http://www.linuxjournal.com/content/return-values-bash-functions

NOTA: A função isdirectory é apenas para fins instrucionais. Não deve ser assim que você executa essa opção em um script real.

Mike Q
fonte
3
Ou apenas use test -d $1para obter o mesmo resultado. Nunca faça if <check> return else return. <check>sozinho fará a mesma coisa em todos os idiomas que conheço pelo menos.
Erikbwork
4
Para ser ainda mais explícito sobre o que erik está dizendo: isdirectory() { [ -d "$1" ]; }se comportará exatamente como o que você tem aqui: O valor de retorno padrão de uma função shell, seja atingindo o final de seu código ou por um returnsem argumentos, é o comando mais recente.
Charles Duffy
11
Os outros comentaristas aqui estão criticando o estilo do exemplo de Mike Q, quando ele realmente está falando sobre o comportamento da returndeclaração. É verdade que seu exemplo é simplista e não deve ser usado na produção. Mas é simples, por isso realiza sua tarefa muito bem. Nada de errado com isso.
Mike S
Obrigado Mike S, sim, eu concordo que o exemplo mais simples explica melhor saída x retorno. Os outros comentários são certamente válida, e deve ser considerado para mais codificadores festança avançada ;-)
Mike Q
1
Alguns podem dizer que não está exatamente relacionado à pergunta, mas está relacionado e respondeu ao problema que tive que me levou a encontrar essa pergunta. :-)
Jesse Steele
33

Lembre-se de que as funções são internas a um script e normalmente retornam de onde foram chamadas usando a instrução return. Chamar um script externo é outra questão inteiramente, e os scripts geralmente terminam com uma instrução de saída.

A diferença "entre a declaração de retorno e saída nas funções BASH em relação aos códigos de saída" é muito pequena. Ambos retornam um status, não valores per se. Um status zero indica sucesso, enquanto qualquer outro status (1 a 255) indica uma falha. A instrução de retorno retornará ao script de onde foi chamada, enquanto a instrução de saída encerrará o script inteiro de onde for encontrado.

return 0  # returns to where the function was called.  $? contains 0 (success).

return 1  # returns to where the function was called.  $? contains 1 (failure).

exit 0  # exits the script completely.  $? contains 0 (success).

exit 1  # exits the script completely.  $? contains 1 (failure).

Se sua função simplesmente terminar sem nenhuma instrução de retorno, o status do último comando executado será retornado como o código de status (e será colocado em $?).

Lembre-se de retornar e sair devolvendo um código de status de 0 a 255, disponível em $?. Você não pode inserir mais nada em um código de status (por exemplo, retornar "cat"); isso não vai funcionar. Porém, um script pode transmitir 255 motivos diferentes de falha usando códigos de status.

Você pode definir variáveis ​​contidas no script de chamada ou fazer eco dos resultados na função e usar a substituição de comandos no script de chamada; mas o objetivo do retorno e da saída é passar códigos de status, não valores ou resultados de computação, como seria de esperar em uma linguagem de programação como C.

user2100135
fonte
25

Às vezes, você executa um script usando .ou source.

. a.sh

Se você incluir um exitno a.sh, ele não apenas encerrará o script, mas também encerrará sua sessão do shell.

Se você incluir um returnno a.sh, ele simplesmente interromperá o processamento do script.

Juraj
fonte
1
Mas quando apenas executo o a.sh, recebo um erro return: can only 'return' from a function or sourced script, o que o torna inadequado para um script geral.
Peter - Restabelece Monica
No nível superior de um script, nenhum deles é adequado em allsituações. Usar .ou sourceexecutar o script no shell atual, em vez de gerar um sub shell. O script precisa saber como deve ser usado. Ai do usuário que faz o contrário. Pessoalmente, recomendo a leitura de scripts antes de executá-los pela primeira vez.
Jesse Chisholm
3
Um truque incrível que eu me deparei é usar uma trapfunção ERR EXITe, em seguida, primeiro salvar o código de saída de um comando com falha errCode=$?e sair do script (de origem ou não) com o local return $errCode || exit $errCodeonde os ||meios "se eu não puder retornar porque não foi de origem" , basta sair ".
precisa saber é o seguinte
6

Em palavras simples (principalmente para iniciantes em codificação), podemos dizer,

`return` : exits the function,
`exit()` : exits the program(called as process while running)

Além disso, se você observou, isso é muito básico, mas ...,

`return` : is the keyword
`exit()` : is the function
Jyo, o Whiff
fonte
1
Em um script bash, exitnão é mais ou menos uma função do que return. Eles são comandos internos. Nem são palavras reservadas.
Peter - Restabelecer Monica
6
  • exitencerrar o processo atual ; com ou sem código de saída, considere isso um sistema mais que uma função do programa. Observe que, ao fazer o sourcing, exito shell será finalizado; no entanto, ao executar, será apenas exito script.

  • returnde uma função, volte para a instrução após a chamada, com ou sem um código de retorno. returné opcional e está implícito no final da função. returnsó pode ser usado dentro de uma função.

Quero acrescentar que, enquanto estiver sendo originado, não é fácil para exito script de dentro de uma função sem matar o shell. Eu acho que um exemplo é melhor em um script de 'teste'

#!/bin/bash
function die(){
   echo ${1:=Something terrible wrong happen}
   #... clean your trash
   exit 1
}

[ -f /whatever/ ] || die "whatever is not available"
# now we can proceed
echo "continue"

fazendo o seguinte:

user$ ./test
Whatever is not available
user$

test - e - a concha será fechada.

user$ . ./test
Whatever is not available

somente testterminará e o prompt será exibido.

A solução é incluir o potencial procedimento em (e)

#!/bin/bash
function die(){
   echo $(1:=Something terrible wrong happen)
   #... clean your trash
   exit 1
}

( # added        
    [ -f /whatever/ ] || die "whatever is not available"
    # now we can proceed
    echo "continue"
) # added

agora, em ambos os casos, apenas testsairá.

fcm
fonte
Adicionar o bloco (e )colocar esse bloco em um sub shell, efetivamente desabilitando o .comando (origem) como se você tivesse executado o script de teste normalmente, que está em um sub shell. IO script não é executado com .ou sourceentão você possui efetivamente 2 sub-shells.
Jesse Chisholm
3

A pergunta do OP: Qual é a diferença entre a declaração de retorno e saída nas funções BASH em relação aos códigos de saída?

Por fim, alguns esclarecimentos são necessários:

  • Uma instrução (return | exit) não é necessária para finalizar a execução de uma (função | shell). Uma (função | shell) será finalizada quando chegar ao final de sua lista de códigos, mesmo sem a declaração (return | exit).
  • Uma instrução (return | exit) não é necessária para passar um valor de volta de um terminado (função | shell). Todo processo possui uma variável interna $? que sempre tem um valor numérico. É uma variável especial que não pode ser definida como "? = 1", mas é definida apenas de maneiras especiais (veja abaixo *). O valor de $? após o último comando a ser executado no (chamado sub-função | função) é o valor que é passado de volta para o (chamador | função-pai | shell). Isso é verdade se o último comando executado é ("return [n]" | "exit [n]") ou simples ("return" ou qualquer outra coisa que por acaso seja o último comando no código de funções chamado.

Na lista de marcadores acima, escolha entre "(x | y)" sempre o primeiro item ou sempre o segundo item para obter instruções sobre funções e retorno ou shells e saída, respectivamente.

O que está claro é que ambos compartilham o uso comum da variável especial $? para passar valores para cima depois que eles terminam.

* Agora, para as formas especiais que $? Pode ser configurado:

  • Quando uma função chamada termina e retorna ao chamador, $? no chamador será igual ao valor final de $? na função finalizada.
  • Quando um shell pai espera implicitamente ou explicitamente em um único sub shell e é liberado pelo término desse sub shell, então $? no shell pai será igual ao valor final de $? no sub shell finalizado.
  • Algumas funções internas podem modificar $? dependendo do resultado deles. Mas alguns não.
  • Funções internas "return" e "exit", quando seguidas por um argumento numérico, tanto $? com argumento e encerre a execução.

Vale a pena notar que $? pode ser atribuído um valor chamando exit em um sub shell, assim:

# (exit 259)
# echo $?
3  
Craig Hicks
fonte
4
No caso de alguns não entenderem, exit 259ecoam como se 3o valor final de saída fosse um único byte. 259 % 256 = 3
Jesse Chisholm
0

Primeiro de tudo, returné uma palavra-chave e exitmeu amigo é uma função.

Dito isto, aqui está uma das explicações mais simples.

return Retorna um valor de uma função.

exit Ele sai ou abandona o shell atual.

Ahmad Awais
fonte
Na verdade não! Você está logicamente errado. Sair é uma função enquanto returné uma palavra-chave. O retorno é muito mais do que apenas códigos de saída, e é por isso que a comparação não é justa.
Ahmad Awais
Eu o editei para deixar mais claro o que estava tentando mostrar. Obrigado por me ajudar a fazer isso.
Ahmad Awais
4
Nem exitnem returnsão "palavras-chave", ou, como os festança chamadas manuais eles "palavras reservadas". Também não é uma "função", no sentido de uma função bash. Ambos são comandos internos, no idioma do bash. (Não é uma função C biblioteca padrão chamado exit(), e a linguagem de programação C tem uma palavra reservada return, mas aqueles que não deve ser confundido com os comandos bash, apesar de sua semântica são curiosamente similar.)
Peter - Reintegrar Monica