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 ....


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.


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.


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.


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.


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?


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.


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.


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


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.


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


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).


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 ....."

-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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.