Warum hängen einige Befehle das Terminal, bis sie fertig sind?

22

Manchmal führen Sie ein Programm vom Terminal aus aus, z. B. lxpanel . Das Terminal wird Sie nicht zurück zur Eingabeaufforderung bringen, es wird hängen bleiben. Sie können Ctrl+ drücken C, um zur Eingabeaufforderung zurückzukehren, aber das wird töten lxpanel. Das Drücken von Alt+ F2(das ein Fenster öffnet, um einen Befehl entgegenzunehmen) und das Ausführen lxpanelfunktioniert jedoch ordnungsgemäß.

Warum ist das? Was ist der Unterschied zwischen dem Ausführen eines Befehls über das Terminal und dem Ausführen-Fenster, das angezeigt wird, wenn Sie Alt+ drücken F2?

lxpanel wurde hier nur als Beispiel verwendet. Ich habe dies mit mehreren Programmen erlebt

sqram
quelle
1
Tipp: Mit GNU Screen ( screen) können Sie unter anderem länger laufende Prozesse "umbrechen". Sie können die Verbindung trennen, zur Shell zurückkehren, die Verbindung erneut herstellen und die Ausgabe des laufenden Prozesses anzeigen. Das erneute Anschließen kann sogar über ein anderes Terminal, SSH usw. erfolgen. Möglicherweise gibt es auch andere Programme, mit denen Sie solche Aufgaben ausführen können.
Poplitea

Antworten:

28

Standardmäßig führt das Terminal das Programm im Vordergrund aus, sodass Sie erst wieder an der Shell landen, wenn das Programm beendet ist. Dies ist nützlich für Programme, die von stdin lesen und / oder in stdout schreiben - im Allgemeinen möchten Sie nicht, dass viele von ihnen gleichzeitig ausgeführt werden. Wenn Sie möchten, dass ein Programm im Hintergrund ausgeführt wird, können Sie es folgendermaßen starten:

$ lxpanel &

Wenn es bereits ausgeführt wird, können Sie es mit Ctrl+ anhalten Zund dann ausführen bg, um es in den Hintergrund zu verschieben. In beiden Fällen wird eine neue Shell-Eingabeaufforderung angezeigt, das Programm wird jedoch weiterhin ausgeführt und die Ausgabe wird im Terminal angezeigt (sodass es plötzlich angezeigt wird, während Sie gerade tippen).

Einige Programme (normalerweise Daemons) lösen beim Start einen separaten Prozess aus und lassen den Hauptprozess dann sofort beenden. Auf diese Weise kann das Programm weiter ausgeführt werden, ohne die Shell zu blockieren

Michael Mrozek
quelle
Was macht das System eigentlich, wenn Sie das Programm über das 'Ausführen'-Fenster mit Alt + F2 ausführen? (Zumindest bei Gnome und Openbox macht das Alt + F2). Ich frage, denn sobald Sie den Befehl eingeben, startet das Programm und die Box verschwindet. Fügt es nur ein & hinzu?
sqram
2
@lyrae: Standardmäßig wartet die Shell auf den Abschluss des Programms, bevor sie die Shell-Sitzung fortsetzt. Sie "hängt" sich nicht auf, wie "hängt" definiert ist. alt + f2 wartet nicht auf das Programm. Der Grund, warum die Shell auf den Abschluss des Programms wartet, besteht darin, dass die Shell alles, was der Benutzer in die Shell eingegeben hat, zur Standardeingabe des Programms umleiten und / oder die Standardausgabe des Programms anzeigen kann. Da Alt + F2 hauptsächlich zum Starten eines GUI-Programms verwendet wird, bietet Alt + F2 nicht die Möglichkeit, die Standardeingabe / -ausgabe zu verwenden, und muss daher nicht warten.
Lie Ryan
1
@lyrae: Alt + F2 unternimmt keine besonderen Schritte, um das Programm im Hintergrund zu starten. Es ist die Shell, die etwas Besonderes tut. Das Hinzufügen von '&' ist die Funktionalität der Shell. Wenn Sie einen Befehl ohne '&' starten , leitet die Shell die Standardeingabe des Programms an die eigene Standardeingabe und die Standardausgabe des Programms an die eigene Standardausgabe weiter (ein wenig konstruiert, da die Shell auch viele andere Dienste wie das Abfangen von Strg bietet -C, um einen SIGINT-Signalbefehl an das Vordergrundprogramm zu senden). Das '&' weist die Shell an, dies nicht zu tun und nur das Programm zu starten (auch erfunden).
Lie Ryan
1
@LieRyan Einige der Funktionen der Shell werden vom Terminaltreiber des Kernels übernommen, und "with &" ist im Allgemeinen eher "special" als "without &", ansonsten ruft die Shell wait () [oder waitpid oder äquivalent], was mit alt-f2 nicht gemacht wird.
Random832
6

Wenn Sie ein Programm in einem Terminal starten, "hängt" das Terminal, bis Ihr Programm stoppt. Durch Drücken von Ctrl+ cschließen Sie Ihr Programm und kehren zur Eingabeaufforderung zurück. Sie sehen dies bei allen GUI-Apps, zum Beispiel Firefox.

Wenn Sie eine andere Methode wie Alt + F2 verwenden oder durch die Menüs klicken, wird Ihr Programm im Hintergrund gestartet, sodass nichts Ungewöhnliches passiert (und es gibt sowieso keine Eingabeaufforderung).

Wenn Sie GUI-Apps dennoch vom Terminal aus starten möchten, hängen Sie sie wie folgt &an das Ende Ihres Befehls an

lxpanel &

Dies weist das Terminal an, lxpanelim Hintergrund zu laufen und Ihnen sofort eine weitere Eingabeaufforderung zu geben.

phunehehe
quelle
3

Programme, die über eine Shell ausgeführt werden, werden standardmäßig im Vordergrund dieser Shell ausgeführt. Dadurch wird die Shell angehalten und stdin / stdout / sterr vom Terminal an das Programm weitergeleitet. Programme, die über die Desktop-Umgebung ausgeführt werden , werden gegabelt , wodurch sie unabhängig von dem Programm ausgeführt werden, mit dem sie ausgeführt wurden. Dies kann in den meisten Shells durch Anhängen von a &an den Befehl simuliert werden , obwohl dies weiterhin std * mit dem Terminal verbindet (obwohl das Lesen von stdin in einem Hintergrundprogramm weitere Komplikationen mit sich bringt).

Ignacio Vazquez-Abrams
quelle
2

Der & Hintergrund ist gut, mit Ausnahme von Programmen, die später eine Konsoleninteraktion erfordern (z. B. ein "apt -y update &", das schließlich in den STOP-Zustand wechselt, da der Benutzer viel später eine "Wirklich-Wirklich-Kraft" -Frage erhalten soll .... wenn niemand mehr zuschaut).

Um diese Lücke zu schließen und den Prozess darüber zu informieren, dass ein Terminal wirklich niemals verfügbar sein wird, füge ich einigen meiner Befehle ein <& - hinzu, und löse sie vollständig vom aktiven Terminal, um ihnen mitzuteilen, dass STDIN nicht mehr möglich ist. Stellen Sie sicher, dass / bin / bash Ihre Shell ist, wenn Sie das verwenden. Das Skript protokolliert weiterhin alle Fehler, die darauf zurückzuführen sind, dass kein Pseudoterminal verfügbar ist, für das eine Eingabeaufforderung gesendet werden kann.

Beispielsweise:

`./runme.sh &> runme.log <&- & disown`

ist meine ultimative Möglichkeit, mich von der aktuellen Terminalsitzung zu lösen. Sowohl STDOUT als auch STDERR werden in runme.log protokolliert. Es spielt keine Rolle, ob Ihre Konsole oder Shell früher beendet wird oder ob Sie sich bei einem anderen Konto abmelden (kein Terminalmüll von runme) PID-Beziehung wird entfernt.

UPDATE: Trotzdem hatte ich Probleme damit, ein Semaphor mit dem Namen des ursprünglichen Elternteils zu verknüpfen. Deshalb empfehle ich jetzt stattdessen:

at now <<< "(cmd1; cmd2; etc.) &> logfile.log"

Entfernen Sie natürlich das &>, wenn Sie die Ausgabe von CRON per E-Mail erhalten möchten, oder leiten Sie sie statt einer Datei an / dev / null weiter.

Marcos
quelle
Ein etwas weniger komplizierter Weg, den ich zu nutzen begann, istat now <<< "(cmd1; cmd2; etc.) &> logfile.log"
Marcos