web-dev-qa-db-fra.com

Blocage du démarrage du terminal

Si vous tapez cette commande de test simple:

gnome-terminal -x bash -c "ls;sleep 3"

Vous constaterez qu'il revient immédiatement (le terminal nouvellement créé attend évidemment trois secondes). Cela contraste avec, par exemple, rxvt (même commande mais avec e).

Si vous souhaitez un blocage, le consensus historique semble avoir été pour utiliser --disable-factory . Malheureusement, cela ne fonctionne plus (testé en 3.14.2).

Alors, comment démarrer le terminal de manière non asynchrone?

Bonus: konsole, lxterminal et xfce4-terminal ont au moins le même problème. Commandes pour ceux?

5
imallett

J'utilise une méthode qui a quelques similitudes avec la réponse de terdon (et qui a été créée avec l'aide de lui - Merci @ terdon pour ça!), Mais a une approche légèrement différente:

Je crée un fichier temporaire de sorte que le terminal enfant puisse communiquer avec le terminal parent et lui indiquer le PID de son instance bash correspondante. Ensuite, je laisse le terminal parent lire le fichier temporaire et mémoriser le PID, le supprimer et continuer en vérifiant toutes les 100 ms (le délai peut être modifié) si l'instance bash du terminal enfant est toujours en cours d'exécution. Sinon, le terminal a été fermé manuellement ou parce que la commande s'est terminée. Ensuite, la commande de lancement se termine et le terminal parent est à nouveau utilisable.

Avantage de cette approche:
Toutes les commandes qui seront lancées (ls; sleep 3 ou tout remplacement de celles-ci) sont exécutées après la commande responsable de permettre la détection de la fermeture du terminal. Ainsi, si la commande interne se bloque ou si vous fermez le terminal manuellement avant la fin, le mécanisme fonctionne toujours et continue l'exécution du script externe au lieu de s'exécuter dans des boucles infinies.


Le code en une ligne avec sortie de débogage ("lancé" après l'ouverture de la fenêtre du terminal enfant, "terminé" après sa fermeture) avec une précision de 0,1 seconde est le suivant:

pidfile=$(mktemp); gnome-terminal -x bash -c "echo \$$>$pidfile; ls; sleep 3"; until [ -s $pidfile ]; do sleep 0.1; done; terminalpid=$(cat "$pidfile"); rm $pidfile; echo "launched"; while ps -p $terminalpid > /dev/null 2>&1; do sleep 0.1; done; echo "terminated"

Ou sans sortie de débogage:

pidfile=$(mktemp); gnome-terminal -x bash -c "echo \$$>$pidfile; ls; sleep 3"; until [ -s $pidfile ]; do sleep 0.1; done; terminalpid=$(cat "$pidfile"); rm $pidfile; while ps -p $terminalpid > /dev/null 2>&1; do sleep 0.1; done

Presque le même code mais avec plus de flexibilité écrit en script bash:

#! /bin/bash

delay=0.1
pidfile=$(mktemp)

gnome-terminal -x bash -c "echo \$$>$pidfile; ls; sleep 3"

until [ -s $pidfile ] 
    do sleep $delay
done
terminalpid=$(cat "$pidfile")
rm $pidfile
echo "launched"
while ps -p $terminalpid > /dev/null 2>&1
    do sleep $delay
done
echo "terminated"

Vous pouvez bien sûr omettre les lignes echo "launched" et echo "terminated", ainsi que modifier la ligne delay=0.1 en un autre délai entre deux vérifications de l'état du terminal (en secondes) si vous en avez besoin être plus ou moins précis.

Pour exécuter une autre commande personnalisée dans le terminal enfant, remplacez la ligne

gnome-terminal -x bash -c "echo \$$>$pidfile; ls; sleep 3"

avec ce qui suit (insérez votre commande à la place de l'espace réservé en majuscule!)

gnome-terminal -x bash -c "echo \$$>$pidfile; INSERTYOURCOMMANDSHERE"
4
Byte Commander

Dans leur infinie sagesse, les développeurs de GNOME ont décidé de supprimer cette option. Malheureusement, leur sagesse ne s'est pas étendue à la mise à jour de leur page man qui le répertorie toujours. Il semble donc que gnome-terminal sera toujours exécuté en arrière-plan et que la session Shell parent sera immédiatement renvoyée. Pour résoudre ce problème, vous avez plusieurs options:

  1. Il suffit d'utiliser un autre terminal. J'ai essayé avec les terminaisons xterm, rxvt et GNOME, qui ont tous fonctionné comme prévu.

  2. Utilisez des hacks laids. gnome-terminal, lors de la première exécution, lance /usr/lib/gnome-terminal/gnome-terminal-server. Pour une raison quelconque, cela signifie que le processus est terminé dès que vous l'avez lancé. Pour illustrer:

    $ gnome-terminal  -x sh -c "ls;sleep 30" 
    [1] 5896
    $ jobs
    [1]+  Done                    gnome-terminal -x sh -c "ls;sleep 30"
    

    Comme vous pouvez le voir ci-dessus, après le lancement en arrière-plan, le travail lancé se termine immédiatement. Cela signifie que ma première idée de le lancer en arrière-plan, puis d’utiliser $! pour vérifier s’il fonctionne toujours ne fonctionnera pas. Cela signifie que vous devrez faire quelque chose de moins élégant, comme créer un fichier:

    tmpfile=$(mktemp); gnome-terminal  -x sh -c "ls;sleep 30; rm $tmpfile" 
    while [ -e $tmpfile ] ; do :; done
    

    Les commandes ci-dessus créeront un fichier temporaire (tmpfile=$(mktemp)); ii) lance gnome-terminal en lui disant de supprimer $tmpfile une fois terminé et iii) de ne rien faire (:) tant que le fichier temporaire existe while [ -e $tmpfile ]. Cela entraînera un terminal qui attendra que le processus exécuté par gnome-terminal se termine avant de continuer.

3
terdon

Les responsables Ubuntu du paquet gnome-terminal ont remarqué ce problème et ont créé un script de wrapper (dans le paquet Ubuntu gnome-terminal-3.14.2-0ubuntu3) pour réactiver l’option --disable-factory; Cependant, le script d'emballage ne fonctionne pas!

Extrait du changelog http://changelogs.ubuntu.com/changelogs/pool/main/g/gnome-terminal/gnome-terminal_3.14.2-0ubuntu3/changelog :

gnome-terminal (3.14.2-0ubuntu3) vif; urgence = moyenne

  • debian/gnome-terminal: Ajoutez un script de wrapper pour lancer gnome-terminal avec un identifiant d'application différent lorsqu'un utilisateur passe l'option - ignoré - factory désormais ignorée. Cela devrait rétablir la compatibilité avec les anciens lanceurs pour les utilisateurs qui effectuent une mise à niveau. [...]

Je ne peux pas naviguer dans le "Launchpad" d'Ubuntu (tant pour l'open source) mais le script de wrapper se trouve dans https://launchpad.net/ubuntu/+archive/primary/+files/gnome-terminal_3 .14.2-0ubuntu3.debian.tar.xz (appelé gnome-terminal.wrap).

Le problème est que le script gnome-terminal.wrap attend le mauvais processus enfant. il devrait attendre sur le serveur terminal, pas sur le terminal client. Le correctif consiste à modifier les deux méthodes server_appeared et spawn_terminal_server comme suit:

    def server_appeared(self, con, name, owner):
        # start gnome-terminal now
        gt = Gio.Subprocess.new(['/usr/bin/gnome-terminal.real',
                                 '--app-id', name] +
                                self.args,
                                Gio.SubprocessFlags.NONE)
        # removed a line here: gt.wait_async(...)

    def spawn_terminal_server(self, name):
        ts = Gio.Subprocess.new(['/usr/lib/gnome-terminal/gnome-terminal-server',
                                 '--app-id',
                                 name],
                                Gio.SubprocessFlags.NONE)
        ts.wait_async(None, self.exit_loop, ts)

Vous pouvez télécharger le fichier corrigé à partir de: https://Gist.github.com/ecatmur/00893506a23e828c6688 .

J'ai notifié le responsable du paquet, j'espère que cela devrait être corrigé assez rapidement.


Un autre fait intéressant: gnome-terminal peut être construit avec un client alternatif appelé gterminal qui a une option --wait qui semble faire exactement ce que vous voulez. Cependant, malheureusement, Ubuntu ne le construit pas et ne l'installe pas dans son paquet gnome-terminal.

3
ecatmur

Pour les personnes en février 2017 <t <mars 2018, qui sont venues sur ce site via Google, la solution simple est:

gnome-terminal --disable-factory -e "cmd"

fonctionne et démarre gnome-terminal de manière synchrone/bloquante comme prévu.

Testé sous:

  • Ubuntu 16.04
  • gnome-terminal 3.18.3
0
Oscillon

J'utilise un nouveau gnome-terminal, et le comportement que vous avez décrit pour gnome-terminal semble être le même pour konsole, lxterm et rxvt (essayé sur les 3). Donc, comme OP n'a pas répondu à aucun commentaire jusqu'à présent pour clarifier ce qu'il ou elle veut, je suppose que OP veut continuer à utiliser le terminal parent sans attendre la fin du terminal enfant.

Cela peut être réalisé avec gnome-terminal &. Si vous voulez éviter que le terminal enfant ne soit fermé lors de la fermeture du parent, utilisez Nohup gnome-terminal &. Pour éviter de voir une sortie d'erreur dans le terminal parent, utilisez gnome-terminal 2> /dev/null & ou Nohup gnome-terminal 2> /dev/null &.

0