Beenden Sie das Terminal, nachdem Sie ein Bash-Skript ausgeführt haben

18

Ich versuche, ein bashSkript zu schreiben , um bestimmte Dateien (hauptsächlich PDF-Dateien) mit dem gnome-openBefehl zu öffnen . Ich möchte auch, dass das Terminal beendet wird, sobald es die PDF-Datei öffnet.

Ich habe versucht, exitan das Ende meines Skripts hinzuzufügen , aber das Terminal wird nicht geschlossen. Ich habe versucht, online nach einer Antwort auf meine Frage zu suchen, aber ich konnte keine richtige finden. Ich würde es wirklich begrüßen, wenn ihr helfen könntet.

Ich brauche eine Antwort, die nur das Terminal beendet, von dem aus ich den Befehl ausführe. Sind nicht alle Terminals dazu in der Lage? Die vorherige Antwort, die ich akzeptiert habe, löscht alle geöffneten Terminalfenster. Ich wusste bis heute nicht, dass dies der Fall ist.

Rumesh
quelle
Führen Sie das Skript zunächst im Terminal aus? Streng von der Kommandozeile aus gibt es keinen Grund, das Terminal dafür zu öffnen.
Jacob Vlijm
Ja, ich führe das Skript vom Terminal aus. Ich wusste nicht, dass es einen Unterschied zwischen Terminal und Kommandozeile gibt
Rumesh,
Ich ersetzen die gnome-openmit xdg-openin meinem Skript , aber es gibt keine Veränderung. Das Terminal bleibt weiterhin geöffnet
Rumesh 20.04.15
@ Tim Wow, es funktioniert =) +1
AB
@ Tim Aber meine Lösung war auch nicht schlecht. ;)
AB

Antworten:

12

Wenn Sie nur eine Datei öffnen, müssen Sie eigentlich kein Skript verwenden, da ein Skript eine einfache Möglichkeit ist, mehrere Befehle hintereinander auszuführen, während Sie hier nur zwei Befehle ausführen müssen (einschließlich exit). .

Wenn Sie exitnach einem Befehl oder nach einer Befehlskette ausführen möchten , können Sie ihn mit dem &&Operator (der bei Erfolg des vorherigen Befehls / der vorherigen Befehlskette den nächsten Befehl ausführt) oder mit dem Befehl an das, was Sie bereits haben, ketten ;Operator (der sowohl bei Erfolg als auch bei Fehlschlagen des vorherigen Befehls / der vorherigen Befehlskette den nächsten Befehl ausführt).

In diesem Fall wäre es ungefähr so:

gnome-open <path_to_pdf_file> && exit

* <path_to_pfd_file> = Pfad der PDF-Datei

exitput am Ende eines Skripts funktioniert nicht, da nur die bashInstanz beendet wird, in der das Skript ausgeführt wird. Dies ist eine andere bashInstanz als die innere bashInstanz des Terminals .

Wenn Sie trotzdem ein Skript verwenden möchten, ist es am einfachsten, das Skript wie folgt aufzurufen:

<path_to_script> && exit

Oder wenn sich das Skript wie folgt im aktuellen Arbeitsverzeichnis des Terminals befindet:

./<script> && exit

Wenn Sie das wirklich nicht wollen / können, ist es am zweithäufigsten einfach, diese Zeile am Ende Ihres Skripts einzufügen:

kill -9 $PPID

Dies sendet ein SIGKILLSignal an den übergeordneten Prozess des Skripts (die bashmit dem Terminal verknüpfte Instanz). Wenn nur eine bashInstanz mit dem Terminal verbunden ist, führt der Abbruch dazu, dass sich das Terminal selbst schließt. Wenn mehrere bashInstanzen mit dem Terminal verbunden sind, führt der Abbruch nicht dazu, dass sich das Terminal selbst schließt.

kos
quelle
2
Das SIGTERM-Signal wird an einen Prozess gesendet, um dessen Beendigung anzufordern. Im Gegensatz zum SIGKILL-Signal kann es vom Prozess abgefangen und interpretiert oder ignoriert werden. Auf diese Weise kann der Prozess eine ordnungsgemäße Beendigung durchführen und Ressourcen freigeben und gegebenenfalls den Status speichern. SIGINT ist nahezu identisch mit SIGTERM.
AB
@AB Du hast recht, SIGTERMhier ist nicht genug.
Kos
Danke für die Antwort. Ich
nehme an,
kill $ PPID macht dasselbe wie exit - nichts. Und kill -9 $ PPID schließt alle untergeordneten Fenster zusammen mit dem übergeordneten Fenster.
SDsolar
5

Dieses Skript beendet das Terminal und damit die Shell und sich selbst.

Es bricht gnadenlos alle Prozesse ab. Wenn in einem Terminal mehrere Registerkarten geöffnet sind, werden diese ebenfalls geschlossen.

Das Problem ist, wenn mehrere Terminals geöffnet sind und dies untergeordnete Prozesse von sind gnome-terminal-server, werden alle Terminals getötet.

In diesem Fall sollte das Skript in einem unabhängigen Terminal gestartet werden, z xterm

<your_command> & disown

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

    Die PPID ist die übergeordnete Prozess-ID, in diesem Fall die shell ( e.g. /bin/bash).

  • PPPID

    Die PPPID ist die übergeordnete Prozess-ID der PPID, in diesem Fall das Terminalfenster

  • <your_command> & disown

    In der Bash-Shell wird der Befehl disown builtin verwendet, um Jobs aus der Jobtabelle zu entfernen oder Jobs zu markieren, damit kein SIGHUP-Signal an sie gesendet wird, wenn die übergeordnete Shell dies empfängt (z. B. wenn sich der Benutzer abmeldet).

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

    Ruft den Wert der vierten Spalte der Datei ab /proc/$PPID/stat(z. B. für den /proc/1/statRückgabewert 0)

AB
quelle
Ich denke, der Befehl $$ holt sich die PID des Terminals ... Wäre das eine Alternative? Könnten Sie auch erklären, wie man ablehnt?
Tim
Wie macht dieses Skript das? Ich bin noch neu in der Shell-Skripterstellung, daher kann ich diese Befehle nicht wirklich verstehen. Könnten Sie bitte erklären, wie es das Terminal schließt
Rumesh
1
@Tim Nein, es gibt die Shell in einem Terminal zurück: ps xa | grep $$=> 4381 pts/0 Ss 0:01 /usr/bin/zsh
AB
1
@RumeshSudhaharan Löscht das gesamte Terminalfenster, in dem das Skript gestartet wurde, jedoch keine anderen Terminalfenster.
AB
3
@AB Sie haben zuvor gesagt, dass dies nur das aktuelle Terminalfenster und keines der anderen Fenster abbricht. Ich habe dieses Skript heute mit zwei geöffneten Terminalfenstern verwendet und beide wurden getötet, als ich das Skript ausgeführt habe.
Rumesh
4

Sie können verwenden .exec ./your-script

Ein Terminal-Emulator wie GNOME Terminal wird beendet, wenn der darin ausgeführte erste Prozess - normalerweise eine Shell - beendet wird.

Wenn Sie sich bereits in einem Terminal befinden und Sie vor dem Beenden dieses Terminals nur noch ein bestimmtes Skript (oder Programm) ausführen möchten, benötigen Sie die Shell, die in diesem Terminal ausgeführt wird, nicht mehr. So können Sie die execeingebaute Shell verwenden, um die Shell zu erstellen durch den von Ihrem Befehl erstellten Prozess zu ersetzen .

  • Im Fall Ihres Skripts ist das ein weiterer Shell-Prozess - genau wie in einer Sekunde Shell-Prozess erstellt wird, wenn Sie ein Skript ohne ausführen exec.

Die Syntax lautet exec command z .exec ./your-script

exec: ein Beispiel

Angenommen, ich habe ein Shell-Skript namens count, das als ausführbar markiert ist und sich im aktuellen Verzeichnis befindet. Es beinhaltet:

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

Und in einem Terminal laufe ich:

exec ./count

Dies druckt die Ziffern 5, 4, 3,2 , und 1, eine pro Sekunde, und dann das Terminal - Fenster schließt.

Wenn Sie dies von einem anderen Prozess als dem ersten ausführen, der in Ihrem Terminal ausgeführt wird - wenn Sie beispielsweise bashzuerst eine andere Shell-Instanz gestartet haben -, kehren Sie zu der Shell zurück, die diesen Prozess erstellt hat, anstatt das Terminal zu beenden. (Diese Einschränkung gilt auch für exitMethoden auf der Grundlage von.)

Sie können verwenden ../your-script; exit

Wenn Sie nicht möchten, dass sich Ihre Shell durch den neuen Prozess (über exec) ersetzt, können Sie festlegen, dass sie weiterhin aktiv bleibt, sich jedoch sofort nach Abschluss des neuen Prozesses selbst beendet.

Führen Sie dazu Ihren Befehl und den exitdurch getrennte Befehle aus, ;damit sie in einer Zeile angegeben werden können.

Die Syntax lautetcommand; exit z ../your-script; exit

command; exit gegen command && exit

Sie werden feststellen, dass dies der in den Antworten von kos und heemayl vorgeschlagenen Methode ähnelt . Der Unterschied ist, dass:./your-script && exit

  • &&Führt den zweiten Befehl nur aus, wenn der erste Befehl durch Zurückgeben eines Beendigungscodes von Null als erfolgreich gemeldet wurde .
  • ; Führt den zweiten Befehl aus, unabhängig davon, ob der erste Befehl erfolgreich war oder nicht.

Welches Sie möchten, hängt von der jeweiligen Situation ab. Wenn der Befehl fehlschlägt, soll die aufrufende Shell (und das Hosting-Terminal) aktiv bleiben? Wenn ja, verwenden Sie &&; wenn nicht, benutze ;.

Es gibt auch command || exit, die die aufrufende Shell nur beendet, wenn ein Fehlercommand gemeldet wird .

Eliah Kagan
quelle
2

Sie könnten Ihr Skript als Quelle verwenden, anstatt es auszuführen, z

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

Persönlich würde ich den Befehl ausführen, um PDF- oder andere Dateien in der Subshell zu öffnen, eine Verzögerung zu setzen, um die Dateien öffnen zu lassen und dann zu beenden. Grundsätzlich habe ich Folgendes getestet(nohup gnome-open *.pdf &); sleep 2; exit

Variation darüber wäre nohup gnome-open *.pdf && sleep 2 && exit

Sergiy Kolodyazhnyy
quelle
In meinem Fall, da nohupignoriert das Auflegen-Signal, nohup xdg-open some_programarbeitete für mich und exitwar nicht erforderlich . nohupnohup.outnohup: ignoring input and appending output to nohup.out
Leitet
0

Die einfachste Lösung wäre:

xdg-open file.pdf && exit

Im Gegensatz zu anderen ähnlichen nohupBefehlen SIGHUP, die nicht zum Ignorieren des Befehls benötigt werden , xdg-openwird beim Starten eines untergeordneten Prozesses, der die bevorzugte Anwendung zum Öffnen der PDF-Datei ist, das Starten beendet. Da der eigentliche Prozess, der vom Terminal gestartet wird, nicht mehr zum Abbruch da ist, nohupwird er nicht benötigt.

&&Gibt an, dass der nächste Befehl ausgeführt wird, wenn der vorherige Befehl erfolgreich ist, dh den Beendigungscode 0( $?=0) zurückgibt und exitdas Terminal einfach schließt.

heemayl
quelle
Ich glaube, er hat gesagt, dass der Ausgang nicht funktioniert hat ...
Tim
@ Tim: Vielleicht hat OP es nicht richtig benutzt, von der Frage her ist es mir sehr unklar, wie er / sie es exitzum Schluss gebracht hat und nicht funktioniert hat ..
heemayl 20.04.15
1
@Tim Da OP exitin das Skript eingefügt wird, ist dies unbrauchbar, da dadurch die bashInstanz beendet wird, in der das Skript ausgeführt wird, und nicht die übergeordnete bashInstanz (die mit dem Terminal verknüpfte Instanz), wodurch das Terminal geschlossen wird
Kos
1
Auf jeden Fall xdg-openläuft es bereits im Hintergrund und ist nicht mit dem Terminal verbunden, sodass Sie es hier nicht benötigen. Soweit ich weiß nohup, wird OP xdg-openmehrmals in einem Skript ausgeführt, um mehrere Dateien im Batch zu öffnen, xdg-openwenn das Skript so verwendet wird beim ersten xdg-openAuftreten zu verlassen
kos
@kos: Nein, ich bin nicht aktiv xdg-openin der backgr, auch wenn ich hatte nohupaus einem anderen Grund ist & muss there..any Hintergrundprozess von Ursprungsterminal wird getötet werden , wenn Sie das übergeordnete Terminal töten .. nohupist es zu verhindern , es..wenn ich das terminal nicht mehr interaktiv benutzen muss, muss der prozess nicht mehr in bg..auf deinen 2. punkt gesetzt werden, was auch verhindert werden kann, indem jeder xdg-open && exitin einer subshell ausgeführt wird ..
heemayl
0

Um die Titelfrage explizit zu beantworten,

"Terminal verlassen, nachdem ein Bash-Skript ausgeführt wurde" :

Führen Sie nur Ihr Skript im Terminal aus

Ohne die Details zu betrachten, die das Skript ausführt, kann ein Skript mit der Option -e( --command) direkt in einem Terminal ausgeführt werden , ohne eine Shell zu starten - es wird dann anstelle der Shell verwendet:

gnome-terminal -e ./script.sh

Verwenden Sie die Option -x( --execute), wenn Sie dem Skript Argumente bereitstellen möchten. Dabei wird nur der gesamte Rest der Befehlszeile als Befehl und Argument verwendet.

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

Wenn Ihr Skript beendet wird, gibt es keine interaktive Shell, die auf Benutzereingaben warten könnte.

Beispiele

Das Teminal wird nur beendet, nachdem der darin ausgeführte Befehl beendet wurde. So wird es geschlossen, nachdem sleepes 4 Sekunden ohne Shell ausgeführt wurde:

gnome-terminal -x sleep 4

Natürlich können Sie weiterhin Shell-Skripte verwenden, da Ihr Skript ohnehin eine andere Shell-Instanz verwendet.

Sie können eine Shell auch mit einem expliziten Skript ausführen - sie ist nicht interaktiv:

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