Quitter le terminal après avoir exécuté un script bash

18

J'essaie d'écrire un bashscript pour ouvrir certains fichiers (principalement des fichiers pdf) en utilisant la gnome-opencommande. Je veux également que le terminal se ferme une fois qu'il ouvre le fichier pdf.

J'ai essayé d'ajouter exità la fin de mon script mais cela ne ferme pas le terminal. J'ai essayé de chercher en ligne une réponse à ma question, mais je n'ai pas trouvé de réponse appropriée, j'apprécierais vraiment si vous pouviez aider.

J'ai besoin d'une réponse qui ne tue que le terminal à partir duquel j'exécute la commande tous les terminaux ne seraient-ils pas possibles? La réponse précédente que j'ai acceptée tue toutes les fenêtres de terminal ouvertes. Je n'ai pas réalisé que c'était le cas jusqu'à aujourd'hui.

Rumesh
la source
Exécutez-vous le script dans le terminal en premier lieu? Strictement depuis la ligne de commande, il n'y a aucune raison d'ouvrir le terminal pour le faire.
Jacob Vlijm
Oui, je lance le script depuis le terminal. Je ne savais pas qu'il y avait une différence entre le terminal et la ligne de commande
Rumesh
J'ai remplacé le gnome-openpar xdg-opendans mon script mais il n'y a aucun changement. Le terminal reste ouvert
Rumesh
@Tim Wow, ça marche =) +1
AB
@Tim Mais ma solution n'était pas mauvaise non plus. ;)
AB

Réponses:

12

Si vous ouvrez un seul fichier, vous n'avez pas vraiment besoin d'utiliser un script, car un script est censé être un moyen facile d'exécuter plusieurs commandes d'affilée, alors qu'ici vous n'avez qu'à exécuter deux commandes (y compris exit) .

Si vous voulez courir exit après une commande ou après une chaîne de commandes, vous pouvez l'enchaîner à ce que vous avez déjà en utilisant l' &&opérateur (qui, en cas de succès de la commande / chaîne de commandes précédente exécutera la commande suivante) ou en utilisant le ;opérateur (qui, en cas de succès ou d'échec de la commande / chaîne de commandes précédente, exécutera la commande suivante).

Dans ce cas, ce serait quelque chose comme ça:

gnome-open <path_to_pdf_file> && exit

* <path_to_pfd_file> = chemin du fichier pdf

exitmettre à la fin d'un script ne fonctionne pas car il quitte simplement l' bashinstance dans laquelle le script est exécuté, ce qui est un autrebash instance que l' bashinstance interne du terminal .

Si vous souhaitez utiliser un script de toute façon, la façon la plus simple consiste à simplement appeler le script comme suit:

<path_to_script> && exit

Ou si le script se trouve dans le répertoire de travail actuel du terminal comme ceci:

./<script> && exit

Si vous ne voulez vraiment pas / ne pouvez pas faire cela, la deuxième façon la plus simple consiste à ajouter cette ligne à la fin de votre script:

kill -9 $PPID

Cela enverra un SIGKILLsignal au processus parent du script (l' bashinstance liée au terminal). Si une seule bashinstance est liée au terminal, cette suppression entraînera la fermeture du terminal. Si plusieurs bashinstances sont liées au terminal, le fait de le tuer ne provoquera pas la fermeture du terminal.

kos
la source
2
Le signal SIGTERM est envoyé à un processus pour demander sa fin. Contrairement au signal SIGKILL, il peut être capturé et interprété ou ignoré par le processus. Cela permet au processus d'effectuer une belle terminaison en libérant des ressources et en sauvegardant l'état le cas échéant. SIGINT est presque identique à SIGTERM.
AB
@AB Vous avez raison, cela SIGTERMne suffit pas.
kos
Merci pour la réponse. Je suppose que je vais utiliser la seule commande que vous avez donnée dans votre réponse
Rumesh
kill $ PPID fait la même chose que exit - rien. Et kill -9 $ PPID ferme toutes les fenêtres enfants avec le parent.
SDsolar
5

Ce script termine le terminal et donc le shell et lui-même.

Il tue sans pitié tous les processus. Si plusieurs onglets sont ouverts dans un terminal, ils sont également fermés.

Le problème est que si plusieurs terminaux sont ouverts et qu'il s'agit de processus enfants gnome-terminal-server, tous les terminaux seront tués.

Dans ce cas, le script doit être démarré dans un terminal indépendant, par exemple xterm

<your_command> & disown

PPPID=$(awk '{print $4}' "/proc/$PPID/stat")
kill $PPPID
  • PPID

    Le PPID est l'ID du processus parent, dans ce cas le shell ( e.g. /bin/bash)

  • PPPID

    Le PPPID est l'ID de processus parent du PPID, dans ce cas, la fenêtre du terminal

  • <your_command> & disown

    Dans le shell bash, la commande intégrée disown est utilisée pour supprimer des travaux de la table des travaux ou pour marquer des travaux afin qu'aucun signal SIGHUP ne leur soit envoyé si le shell parent le reçoit (par exemple si l'utilisateur se déconnecte).

  • awk '{print $4}' "/proc/$PPID/stat"

    Obtient la valeur de la quatrième colonne du fichier /proc/$PPID/stat(par exemple, car /proc/1/statil renvoie 0)

UN B
la source
Je pense que la commande $$ get est le pid du terminal ... Serait-ce une alternative? Pourriez-vous également expliquer comment renier?
Tim
Comment ce script fait-il cela? Je suis encore nouveau dans les scripts shell, donc je ne peux pas vraiment comprendre ces commandes. Pourriez-vous s'il vous plaît expliquer comment il ferme le terminal
Rumesh
1
@Tim Non, il retourne le shell dans un terminal: ps xa | grep $$=> 4381 pts/0 Ss 0:01 /usr/bin/zsh
AB
1
@RumeshSudhaharan Il tue toute la fenêtre de terminal dans laquelle le script est démarré, mais pas d'autres fenêtres de terminal.
AB
3
@AB vous avez dit précédemment que cela ne tue que la fenêtre de terminal actuelle et pas les autres. J'ai utilisé ce script aujourd'hui avec deux fenêtres de terminal ouvertes et les deux ont été tuées une fois que j'ai exécuté le script.
Rumesh
4

Vous pouvez utiliser .exec ./your-script

Un émulateur de terminal comme GNOME Terminal se ferme lorsque le processus initial qui s'exécute à l'intérieur - qui est généralement un shell - se ferme.

Si vous êtes déjà dans un terminal et que la seule chose que vous voulez faire avant de quitter ce terminal est d'exécuter un script (ou programme) particulier, cela signifie que vous n'avez plus vraiment besoin du shell qui y est exécuté. Ainsi, vous pouvez utiliser la fonction execintégrée du shell pour que le shell se remplace par le processus créé par votre commande.

  • Dans le cas de votre script, c'est un autre processus shell - tout comme la façon dont un deuxième processus shell est créé lorsque vous exécutez un script sans exec.

La syntaxe est , par exemple, .exec commandexec ./your-script

exec: un exemple

Par exemple, supposons que j'ai un script shell appelé count, marqué exécutable et situé dans le répertoire courant. Il contient:

#!/usr/bin/env bash
for i in {5..1}; do echo $i; sleep 1; done

Et, dans un terminal, je lance:

exec ./count

Imprime les chiffres 5, 4, 3, 2et1 , un par seconde, puis la fermeture du fenêtre de terminal.

Si vous l'exécutez à partir de quelque chose d'autre que le premier processus exécuté dans votre terminal - par exemple, si vous avez exécuté en bashpremier pour démarrer une autre instance de shell - cela vous ramène au shell qui a créé ce processus, plutôt que de quitter le terminal. (Cette mise en garde s'applique également auxexit méthodes basées sur.)

Vous pouvez utiliser ./your-script; exit.

Si vous ne voulez pas dire à votre shell de se remplacer par le nouveau processus (via exec ), vous pouvez lui dire de rester, mais de se quitter immédiatement après la fin du nouveau processus.

Pour ce faire, exécutez votre commande et la exitcommande, séparées par ;afin qu'elles puissent être données sur une seule ligne.

La syntaxe est command; exit, par exemple, ../your-script; exit

command; exit contre. command && exit

Vous remarquerez peut-être que cela ressemble à la méthode suggérée dans les réponses de kos et heemayl . La différence est que:./your-script && exit

  • &&exécute la deuxième commande uniquement si la première commande a signalé qu'elle a réussi en renvoyant un code de sortie de zéro.
  • ; exécute la deuxième commande, que la première commande ait ou non rapporté un succès.

Lequel vous voulez dépend de la situation spécifique. Si la commande échoue, voulez-vous que le shell appelant (et le terminal d'hébergement) reste actif? Si oui, utilisez &&; sinon, utilisez; .

Il y a aussi command || exit, qui ne quitte le shell appelant qu'en cas d' écheccommand signalé .

Eliah Kagan
la source
2

Vous pouvez source votre script au lieu de l'exécuter par exemple

$ cat run.sh
exit;
$ ./run.sh #will not close
$ . ./run.sh # will close
RiaD
la source
1

Personnellement, j'exécuterais la commande pour ouvrir un fichier pdf ou d'autres fichiers en sous-shell, mettre un délai pour laisser les fichiers s'ouvrir, puis quitter. En gros, voici ce que j'ai testé(nohup gnome-open *.pdf &); sleep 2; exit

Une variation à ce sujet serait nohup gnome-open *.pdf && sleep 2 && exit

Sergiy Kolodyazhnyy
la source
Dans mon cas, depuis nohupignore le signal de raccrochage, a nohup xdg-open some_programfonctionné pour moi et exitn'a pas été nécessaire. nohupredirige le message vers un nohup.outfichier:nohup: ignoring input and appending output to nohup.out
nick indiessance
0

La solution la plus simple serait:

xdg-open file.pdf && exit

Contrairement à d'autres commandes similaires qui nohupne sont pas nécessaires pour ignorer la commande SIGHUP, la raison en xdg-openest la sortie d'un processus enfant qui est l'application préférée pour ouvrir le fichier pdf. Comme le processus réel démarré depuis le terminal n'est plus là pour être tué, il nohupn'est pas nécessaire.

&&indique que la prochaine commande sera exécutée si la commande précédente réussit, c'est-à-dire renvoie le code de sortie 0( $?=0) et exitfermera simplement le terminal.

heemayl
la source
Je pense qu'il a dit que la sortie ne fonctionnait pas ...
Tim
@Tim: Peut-être que OP ne l'a pas utilisé de la bonne manière, à partir de la question, il m'est très difficile de savoir comment il / elle a mis exità la fin et n'a pas fonctionné ..
heemayl
1
@Tim Parce que OP place exità l'intérieur du script, ce qui est inutile car il a pour effet de quitter l' bashinstance dans laquelle le script est exécuté plutôt que l' bashinstance parent (celle liée au Terminal), ce qui entraînerait la fermeture du Terminal à la place
kos
1
Quoi qu'il en soit, xdg-opens'exécute déjà en arrière-plan et n'est pas lié au terminal, vous n'avez donc pas besoin nohupici, et d'après ce que je comprends, OP s'exécute xdg-openplusieurs fois dans un script pour ouvrir plusieurs fichiers par lots, en utilisant xdg-opencomme cela à l'intérieur du script, le script provoquerait le script sortir à la première xdg-openoccurrence
kos
@kos: Non, je ne cours pas xdg-opendans le backgr, même si je l'ai nohuppour une raison différente et doit être là..tout processus d'arrière-plan du terminal d'origine sera tué lorsque vous tuerez le terminal parent .. nohupest là pour empêcher il .. comme je n'ai pas besoin d'utiliser à nouveau le terminal de manière interactive, il n'est pas nécessaire de mettre le processus en bg .. sur votre 2ème point qui peut également être empêché en exécutant chacun xdg-open && exitdans un sous-shell ..
heemayl
0

Pour répondre explicitement à la question du titre,

"Quitter le terminal après avoir exécuté un script bash" :

Exécutez uniquement votre script dans le terminal

Sans regarder les détails de ce que fait le script, un script peut être exécuté directement à l'intérieur d'un terminal avec l'option -e( --command), sans démarrer un shell - il est utilisé à la place du shell puis:

gnome-terminal -e ./script.sh

Utilisez l'option -x( --execute) lorsque vous souhaitez fournir des arguments au script. Avec cela, tout le reste de la ligne de commande est considéré comme une commande et des arguments.

gnome-terminal -x ./script.sh foo bar

Si votre script se termine, il n'y a pas de shell interactif qui pourrait contenir quoi que ce soit en attendant l'entrée de l'utilisateur.

Exemples

Le teminal quittera juste après la sortie de la commande en cours d'exécution - comme ceci, la fermeture après sleepa fonctionné 4 secondes, sans shell:

gnome-terminal -x sleep 4

Bien sûr, vous pouvez toujours utiliser les scripts shell, car votre script utilise de toute façon une instance shell différente.

De plus, vous pouvez exécuter un shell avec un script explicite - il ne sera pas interactif:

gnome-terminal -x bash -c "echo 'Hello!'; sleep 4"
Volker Siegel
la source