Toute façon de quitter le script bash, mais sans quitter le terminal

183

Lorsque j'utilise la exitcommande dans un script shell, le script met fin au terminal (l'invite). Existe-t-il un moyen de terminer un script et de rester ensuite dans le terminal?

run.shOn s'attend à ce que mon script s'exécute en étant directement issu ou en provenance d'un autre script.

EDIT: Pour être plus précis, il existe deux scripts run2.shcomme

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

et run.shcomme

...
exit
...

quand je le lance . run2.sh, et s'il atteint la ligne de exitcode run.sh, je veux qu'il s'arrête au terminal et y reste. Mais en utilisant exit, tout le terminal se ferme.

PS: j'ai essayé d'utiliser return, mais la echocodeline sera toujours exécutée ...

Richard
la source
5
Je dois vraiment, vraiment, vraiment demander: pourquoi utilisez-vous exit dans un script source?
Ignacio Vazquez-Abrams
3
la commande exit ne doit pas mettre fin à votre session / connexion de terminal. si vous utilisez exit 0pour terminer le script après le succès, lorsque vous exécutez votre script ex: ./test.shvous devriez voir la sortie mais votre console restera ouverte.
Ben Ashton
Vous pouvez utiliser la shellcommande, qui ouvre en fait un terminal shell. Ma propre expérience est cependant que cela ne se produit pas avec exit. Exit redonne normalement le contrôle au script parent.
Willem Van Onsem

Réponses:

258

Le "problème" est vraiment que vous sourcez et que vous n'exécutez pas le script. Lorsque vous sourcez un fichier, son contenu sera exécuté dans le shell actuel, au lieu de générer un sous-shell. Donc, tout, y compris la sortie, affectera le shell actuel.

Au lieu d'utiliser exit, vous voudrez utiliser return.

Dominik Honnef
la source
2
Voici une autre explication que j'ai trouvée utile: askubuntu.com/a/53179/148337
3cheesewheel
Bien que correcte, ce n'est pas une bonne réponse. Il ignore que le script appelant peut déclarer des variables ou des fonctions auxquelles ce script appelé a besoin d'accéder. Mieux vaut expliquer comment définir un code de retour puis le traiter dans runs.sh@ruakh a la meilleure réponse à cette question.
MikeSchinkel
5
Que faire si la fonction est un appel imbriqué? c'est-à-dire que a appelle b, b appelle c, c veut immédiatement quitter a et b.
Michael
La source est presque la même que celle du copier-coller. Il est préférable d'utiliser sh <script>ou bash <script>si l'on veut exécuter un script et terminer à un moment donné
peterchaula
42

Oui; vous pouvez utiliser à la returnplace de exit. Son objectif principal est de retourner à partir d'une fonction shell, mais si vous l'utilisez dans un sourcescript -d, il renvoie à partir de ce script.

Comme le décrit le §4.1 «Bourne Shell Builtins» du Manuel de référence de Bash :

     return [n]

Provoque la fermeture d'une fonction shell avec la valeur de retour n . Si n n'est pas fourni, la valeur de retour est l'état de sortie de la dernière commande exécutée dans la fonction. Cela peut également être utilisé pour terminer l'exécution d'un script en cours d'exécution avec le .(ou source) intégré, renvoyant soit n, soit l'état de sortie de la dernière commande exécutée dans le script comme état de sortie du script. Toute commande associée au RETURNtrap est exécutée avant la reprise de l'exécution après la fonction ou le script. Le statut de retour est différent de zéro s'il returnest utilisé en dehors d'une fonction et non lors de l'exécution d'un script par .ou source.

Ruakh
la source
3
returnpeut UNIQUEMENT être utilisé à partir d'une fonction. Si vous l'utilisez returnet l'exécutez en tant que script shell (par exemple sh run.sh), bash signalera une erreur - return: can only retourne «à partir d'une fonction ou d'un script source»
Tzunghsing David Wong
@TzungsingDavidWong: Vous vous rendez compte que l'essentiel de cette réponse est une citation du manuel de référence officiel? Et que le message d'erreur que vous citez est d'accord avec cette réponse plutôt qu'avec votre réclamation?
ruakh
Je ne suis pas en désaccord avec vous. Je veux simplement souligner que returncela ne fonctionnera pas si le script est exécuté en tant que script shell et non exécuté par. (ou source). BTW, où puis-je trouver le document sur source -d?
Tzunghsing David Wong
9

Au lieu d'exécuter le script en utilisant . run2.sh, vous pouvez l'exécuter en utilisant sh run2.shoubash run2.sh

Un nouveau sous-shell sera lancé, pour exécuter le script ensuite, il se fermera à la fin du script laissant l'autre shell ouvert.

Viorel Mirea
la source
Si oui, alors pourquoi le deuxième paramètre sh "." run2.sh?
CHAN
@ H0WARD Vous avez raison, j'ai oublié de supprimer les points. J'ai édité la réponse maintenant.
Viorel Mirea
1
Le PO indique explicitement la source comme une exigence.
Jonathan Neufeld
4

Vous pouvez ajouter une commande de sortie supplémentaire après l'instruction / la commande de retour afin qu'elle fonctionne pour les deux, en exécutant le script à partir de la ligne de commande et en sourcing depuis le terminal.

Exemple de code de sortie dans le script:

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

La ligne avec la exitcommande ne sera pas appelée lorsque vous sourcez le script après la returncommande.

Lorsque vous exécutez le script, la returncommande génère une erreur. Ainsi, nous supprimons le message d'erreur en le transférant vers /dev/null.

sans nom
la source
3

En fait, je pense que vous pourriez être confus par la façon dont vous devriez run a script.

Si vous utilisez shpour exécuter un script, par exemple, sh ./run2.shmême si le script intégré se termine par exit, votre fenêtre de terminal restera toujours.

Cependant, si vous utilisez .ou source, la fenêtre de votre terminal se fermera / se fermera également à la fin de l'indice.

Pour plus de détails, veuillez consulter Quelle est la différence entre l'utilisation shet source?

Karl Li
la source
2

C'est comme si vous mettiez une fonction d'exécution dans votre script run2.sh. Vous utilisez le code de sortie à l'intérieur de run tout en source votre fichier run2.sh dans le bash tty. Si vous donnez à la fonction run le pouvoir de quitter votre script et donnez au run2.sh le pouvoir de quitter le terminateur. Puis de cuz la fonction run a le pouvoir de quitter votre teminator.

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

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

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

Quoi qu'il en soit, j'approuve avec Kaz c'est un problème de conception.

Umae
la source
Ce que cette réponse tente de faire ne ressort pas clairement du texte, mais elle ne résout certainement pas la question en question.
Luís de Sousa le
2

J'ai eu le même problème et d'après les réponses ci-dessus et d'après ce que j'ai compris, ce qui a fonctionné pour moi était finalement:

  1. Avoir une ligne shebang qui appelle le script prévu, par exemple,

    #!/bin/bashutilise bashpour exécuter le script

J'ai des scripts avec les deux types de shebang. Pour cette raison, utiliser shou .n'était pas fiable, car cela conduisait à une mauvaise exécution (comme lorsque le script renonce à s'exécuter de manière incomplète)

La réponse était donc

    • Assurez-vous que le script a un shebang, de sorte qu'il n'y ait aucun doute sur son gestionnaire prévu.
    • chmod le fichier .sh pour qu'il puisse être exécuté. (chmod +x file.sh)
    • Invoquer directement sans shou.

      (./myscript.sh)

J'espère que cela aide quelqu'un avec une question ou un problème similaire.

gk_2000
la source
1

Je pense que cela se produit parce que vous l'exécutez en mode source avec le point

. myscript.sh

Vous devriez l'exécuter dans un sous-shell:

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

«source» http://ss64.com/bash/source.html

JBoy
la source
Vous n'avez pas besoin du chemin complet du script si cela . myscript.shfonctionne. Tout au plus, vous pourriez avoir besoin ./myscript.sh.
Álvaro González
1

Il est correct que les scripts source et exécutés utilisent returnplutôt que exitpour garder la même session ouverte, comme d'autres l'ont noté.

Voici une astuce connexe, si vous voulez un script qui devrait garder la session ouverte, qu'elle soit ou non d'origine.

L'exemple suivant peut être exécuté directement comme foo.shou généré comme . foo.sh/ source foo.sh. Dans tous les cas, la session restera ouverte après la "sortie". La $@chaîne est transmise afin que la fonction ait accès aux arguments du script externe.

#!/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 "$@";

Résultat final:

$ foo.sh
$ Voulez-vous XYZ? (O / N): n
$. foo.sh
$ Voulez-vous XYZ? (O / N): n
$ |
(la fenêtre du terminal reste ouverte et accepte des entrées supplémentaires)

Cela peut être utile pour tester rapidement les modifications de script dans un seul terminal tout en gardant un tas de code de ferraille sous le main exit/ returnpendant que vous travaillez. Cela pourrait également rendre le code plus portable dans un sens (si vous avez des tonnes de scripts qui peuvent ou non être appelés de différentes manières), bien qu'il soit beaucoup moins maladroit à utiliser returnet le exitcas échéant.

Beejor
la source
0

si votre émulateur de terminal ne l'a pas, -holdvous pouvez nettoyer un script source et maintenir le terminal avec:

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

sinon vous pouvez utiliser $TERM -hold -e script

technosaure
la source
0

Assurez-vous également de retourner avec la valeur de retour attendue. Sinon, si vous utilisez exit lorsque vous rencontrez une sortie, il quittera votre shell de base car la source ne crée pas un autre processus (instance).

codeur23
la source
0

Pour écrire un script qui est sûr d'être exécuté en tant que script shell ou d' origine en tant que fichier rc, le script peut vérifier et comparer $0et $BASH_SOURCEet déterminer si exitpeut être utilisé en toute sécurité.

Voici un court extrait de code pour cela

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

1) exit 0 sortira du script s'il réussit.

2) exit 1 sortira du script s'il s'agit d'un échec.

Vous pouvez essayer ces deux ci-dessus en fonction de votre demande.

Teja
la source