Qualquer maneira de sair do script bash, mas sem sair do terminal

183

Quando eu uso o exitcomando em um script de shell, o script finaliza o terminal (o prompt). Existe alguma maneira de finalizar um script e depois permanecer no terminal?

run.shÉ esperado que meu script seja executado diretamente, ou de outro script.

EDIT: Para ser mais específico, existem dois scripts run2.shcomo

...
. run.sh
echo "place A"
...

e run.shcomo

...
exit
...

quando eu passar por ele . run2.sh, e se ele chegar exitna linha de código run.sh, quero que ele pare no terminal e fique lá. Mas exit, usando , todo o terminal é fechado.

PS: Eu tentei usar return, mas o echocodeline ainda será executado ....

Richard
fonte
5
Eu realmente, realmente, realmente tenho que perguntar: por que você está usando exit em um script de origem?
Ignacio Vazquez-Abrams
3
o comando exit não deve encerrar sua sessão / login no terminal. se você usar exit 0para finalizar o script após o sucesso, quando executar o script ex: ./test.shdeverá ver a saída, mas o console permanecerá aberto.
Ben Ashton
Você pode usar o shellcomando, que abre de fato um terminal shell. Minha própria experiência, porém, é que isso não acontece com exit. Sair normalmente devolve o controle ao script pai.
Willem Van Onsem 9/03/12

Respostas:

258

O "problema" realmente é que você está adquirindo e não executando o script. Quando você origina um arquivo, seu conteúdo será executado no shell atual, em vez de gerar um subshell. Portanto, tudo, incluindo a saída, afetará o shell atual.

Em vez de usar exit, você desejará usar return.

Dominik Honnef
fonte
2
Aqui está outra explicação que eu achei úteis: askubuntu.com/a/53179/148337
3cheesewheel
Embora correta, essa não é uma ótima resposta. Ele ignora que o script de chamada possa declarar variáveis ​​ou funções às quais esse script de script precisa acessar. Melhor explicar como definir um código de retorno e processá-lo no runs.sh@ruakh tem a melhor resposta para essa pergunta.
MikeSchinkel
5
E se a função for uma chamada aninhada? ou seja, a chama b, b chama c, c deseja sair imediatamente de a e b.
Michael
A origem é quase o mesmo que copiar e colar. É melhor usar sh <script>ou bash <script>se alguém quiser executar um script e terminar em algum momento
peterchaula
42

Sim; você pode usar em returnvez de exit. Seu principal objetivo é retornar de uma função shell, mas se você a usar em um sourcescript -d, ela retornará desse script.

Como §4.1 "Bourne Shell Builtins" do Manual de Referência do Bash coloca:

     return [n]

Faça com que uma função shell saia com o valor de retorno n . Se n não for fornecido, o valor retornado é o status de saída do último comando executado na função. Isso também pode ser usado para encerrar a execução de um script sendo executado com o .(ou source) embutido, retornando n ou o status de saída do último comando executado dentro do script como o status de saída do script. Qualquer comando associado à RETURNinterceptação é executado antes da execução continuar após a função ou script. O status de retorno é diferente de zero se returnfor usado fora de uma função e não durante a execução de um script por .ou source.

ruakh
fonte
3
returnsó pode ser usado a partir de uma função. Se você usar returne executá-lo como um script shell (por exemplo sh run.sh), o bash irá relatar um erro - return: can only retorno de uma função ou script` origem
Tzunghsing David Wong
@TzungsingDavidWong: Você percebe que a maior parte desta resposta é uma citação do manual de referência oficial? E que a mensagem de erro que você cita concorda com esta resposta e não com sua reivindicação?
ruakh 21/09/18
Não discordo de você. Quero apenas ressaltar que returnnão funcionará se o script for executado como um shell script e não executado por. (ou source) Aliás, onde posso encontrar o documento source -d?
David David Wong
9

Em vez de executar o script usando . run2.sh, você pode executá-lo usando sh run2.shoubash run2.sh

Um novo sub-shell será iniciado e, para executar o script, será fechado no final do script, deixando o outro shell aberto.

Viorel Mirea
fonte
Se sim, então por que o segundo parâmetro sh "." run2.sh?
CHAN
@ H0WARD Você está certo, eu esqueci de remover os pontos. Eu editei a resposta agora.
Viorel Mirea
1
O OP declara explicitamente a origem como um requisito.
Jonathan Neufeld
4

Você pode adicionar um comando de saída extra após a declaração / comando de retorno, para que funcione para ambos, executando o script na linha de comando e utilizando o terminal.

Exemplo de código de saída no script:

   if [ $# -lt 2 ]; then
     echo "Needs at least two arguments"
     return 1 2>/dev/null
     exit 1
   fi

A linha com o exitcomando não será chamada quando você originar o script após o returncomando.

Quando você executa o script, o returncomando apresenta um erro. Portanto, suprimimos a mensagem de erro encaminhando-a para /dev/null.

noname
fonte
3

Na verdade, acho que você pode estar confuso com a forma como muda run a script.

Se você shcostuma executar um script, digamos, sh ./run2.shmesmo que o script incorporado termine com exit, sua janela de terminal ainda permanecerá.

No entanto, se você usar .ou source, sua janela do terminal também será encerrada / fechada quando o subscrito terminar.

para mais detalhes, consulte Qual é a diferença entre usar she source?

karl li
fonte
2

É assim que você coloca uma função de execução dentro do script run2.sh. Você usa o código de saída dentro de run enquanto origina seu arquivo run2.sh no bash tty. Se a função fornecer a execução tiver o poder de sair do seu script e a run2.sh o poder de sair do terminador. Então, porque a função de execução tem poder para sair do seu teminador.

    #! /bin/sh
    # use . run2.sh

    run()
    {
        echo "this is run"
        #return 0
        exit 0
    }

    echo "this is begin"
    run
    echo "this is end"

Enfim, eu aprovo com Kaz que é um problema de design.

Umae
fonte
Não está claro no texto o que essa resposta tenta fazer, mas certamente não resolve a questão em questão.
Luís de Sousa
2

Eu tive o mesmo problema e pelas respostas acima e pelo que entendi o que funcionou para mim, em última análise, foi:

  1. Tenha uma linha shebang que chama o script pretendido, por exemplo,

    #!/bin/bashusa bashpara executar o script

Eu tenho scripts com os dois tipos de shebang. Por causa disso, usar shou .não é confiável, pois leva a uma execução incorreta (como quando o script falha por executar incompletamente)

A resposta, portanto, foi

    • Verifique se o script possui um shebang, para que não haja dúvidas sobre o manipulador pretendido.
    • chmod o arquivo .sh para que ele possa ser executado. (chmod +x file.sh)
    • Invocá-lo diretamente, sem qualquer shou.

      (./myscript.sh)

Espero que isso ajude alguém com uma pergunta ou problema semelhante.

gk_2000
fonte
1

Eu acho que isso acontece porque você está executando no modo de fonte com o ponto

. myscript.sh

Você deve executar isso em um subshell:

/full/path/to/script/myscript.sh

'source' http://ss64.com/bash/source.html

JBoy
fonte
Você não precisa de um caminho completo para o script, se . myscript.shfuncionar. No máximo, você pode precisar ./myscript.sh.
Álvaro González
1

É correto que os scripts originados x executados usem returnvs. exitpara manter a mesma sessão aberta, como outros observaram.

Aqui está uma dica relacionada, se você quiser um script que mantenha a sessão aberta, independentemente de sua origem ou não.

O exemplo a seguir pode ser executado diretamente como foo.shou originado como . foo.sh/ source foo.sh. De qualquer forma, manterá a sessão aberta após "sair". A $@cadeia é passada para que a função tenha acesso aos argumentos do script externo.

#!/bin/sh
foo(){
    read -p "Would you like to XYZ? (Y/N): " response;
    [ $response != 'y' ] && return 1;
    echo "XYZ complete (args $@).";
    return 0;
    echo "This line will never execute.";
}
foo "$@";

Resultado terminal:

$ foo.sh
$ Gostaria de XYZ? (S / N): n
$. foo.sh
$ Você gostaria de XYZ? (S / N): n
$ |
(a janela do terminal permanece aberta e aceita entrada adicional)

Isso pode ser útil para testar rapidamente as alterações de script em um único terminal, mantendo um monte de código de sucata embaixo do principal exit/ returnenquanto você trabalha. Também poderia tornar o código mais portátil em certo sentido (se você tiver vários scripts que podem ou não ser chamados de maneiras diferentes), embora seja muito menos complicado usar returne exitquando apropriado.

Beejor
fonte
0

se o seu emulador de terminal não tiver, -holdvocê pode limpar um script de origem e manter o terminal pressionado com:

#!/bin/sh
sed "s/exit/return/g" script >/tmp/script
. /tmp/script
read

caso contrário, você pode usar $TERM -hold -e script

technosaurus
fonte
0

Certifique-se também de retornar com o valor esperado. Caso contrário, se você usar exit quando encontrar uma saída, ela sairá do shell base, pois a origem não cria outro processo (instância).

coder23
fonte
0

Para escrever um script que é seguro para ser executado como um script shell ou de origem como um arquivo rc, o script pode verificar e comparar $0e $BASH_SOURCEe determinar se exitpode ser usado com segurança.

Aqui está um trecho de código curto para esse

[ "X$(basename $0)" = "X$(basename $BASH_SOURCE)" ] && \
    echo "***** executing $name_src as a shell script *****" || \
    echo "..... sourcing $name_src ....."
David David Wong
fonte
-1

1) a saída 0 sairá do script se for bem-sucedida.

2) a saída 1 sairá do script se houver falha.

Você pode tentar estes acima de dois com base no seu req.

Teja
fonte