Wie trenne ich einen Prozess vollständig vom Terminal?

304

Ich verwende Tilda (Dropdown-Terminal) unter Ubuntu als "Befehlszentrale" - so wie andere GNOME Do, Quicksilver oder Launchy verwenden.

Ich habe jedoch Probleme damit, einen Prozess (z. B. Firefox) vollständig von dem Terminal zu trennen, von dem aus er gestartet wurde, dh zu verhindern, dass ein solcher (nicht-) untergeordneter Prozess ausgeführt wird

  • wird beim Schließen des Ursprungs-Terminals beendet
  • "verschmutzt" das Ursprungsendgerät über STDOUT / STDERR

Um beispielsweise Vim in einem "richtigen" Terminalfenster zu starten, habe ich ein einfaches Skript wie das folgende ausprobiert:

exec gnome-terminal -e "vim $@" &> /dev/null &

Dies führt jedoch immer noch zu Umweltverschmutzung (auch das Übergeben eines Dateinamens scheint nicht zu funktionieren).

slhck
quelle
1
Auch das ist eine gute Frage. Ich denke, es ist fair, Bash als Programmiersprache zu betrachten - obwohl der Umfang dieser Frage wahrscheinlich eher auf der Seite des
Dies ist ein Duplikat dieser Frage stackoverflow.com/questions/285015/…
Dana the Sane
Ihr Anwendungsfall beschreibt nicht per se die vollständige Ablösung.
Jiggunjer

Antworten:

344

Als erstes; Sobald Sie einen Prozess gestartet haben, können Sie ihn im Hintergrund anzeigen, indem Sie ihn zuerst anhalten (drücken Sie Ctrl- Z) und dann eingeben bg, damit er im Hintergrund fortgesetzt wird. Es ist jetzt ein "Job", und seine stdout/ stderr/ stdinsind immer noch mit Ihrem Terminal verbunden.

Sie können einen Prozess im Hintergrund sofort starten, indem Sie ein "&" an dessen Ende anhängen:

firefox &

Verwenden Sie diese Option, um es im Hintergrund stumm zu schalten:

firefox </dev/null &>/dev/null &

Einige zusätzliche Informationen:

nohupist ein Programm, mit dem Sie Ihre Anwendung so ausführen können, dass stattdessen stdout / stderr an eine Datei gesendet werden kann und das Schließen des übergeordneten Skripts das untergeordnete Skript nicht SEHT. Sie müssen jedoch die Voraussicht gehabt haben, um es zu verwenden, bevor Sie die Anwendung gestartet haben. Aufgrund der Funktionsweise nohupkönnen Sie es nicht einfach auf einen laufenden Prozess anwenden .

disownist eine integrierte Bash, die einen Shell-Job aus der Job-Liste der Shell entfernt. Was dies bedeutet im Grunde , dass Sie nicht verwenden können fg, bgauf es mehr, aber noch wichtiger ist , wenn Sie Ihre Shell schließen wird es nicht hängen oder senden SIGHUPmehr an das Kind. Im Gegensatz zu nohup, disownverwendet wird , nachdem der Prozess gestartet und hintergründig ist.

Was Sie nicht tun können, ist die stdout / stderr / stdin eines Prozesses zu ändern, nachdem Sie ihn gestartet haben. Zumindest nicht aus der Schale. Wenn Sie Ihren Prozess starten und ihm mitteilen, dass seine Standardausgabe Ihr Terminal ist (was Sie standardmäßig tun), ist dieser Prozess für die Ausgabe auf Ihrem Terminal konfiguriert. Ihre Shell hat nichts mit dem FD-Setup der Prozesse zu tun, das ist nur etwas, was der Prozess selbst verwaltet. Der Prozess selbst kann entscheiden, ob stdout / stderr / stdin geschlossen werden soll oder nicht, aber Sie können Ihre Shell nicht verwenden, um dies zu erzwingen.

Um die Ausgabe eines Hintergrundprozesses zu verwalten, stehen zahlreiche Optionen aus Skripten zur Verfügung, wobei "nohup" wahrscheinlich die ersten sind, die in den Sinn kommen. Aber für interaktive Prozesse, die Sie starten, aber vergessen haben, ( firefox < /dev/null &>/dev/null &) zum Schweigen zu bringen , können Sie nicht wirklich viel tun.

Ich empfehle dir GNU screen. Mit screen können Sie einfach Ihre laufende Shell schließen, wenn die Ausgabe des Prozesses störend wird, und eine neue öffnen ( ^Ac).


Oh, und übrigens, benutzen Sie " $@" nicht dort, wo Sie es benutzen.

$@bedeutet, $1, $2, $3..., die Ihren Befehl in drehen würden:

gnome-terminal -e "vim $1" "$2" "$3" ...

Das ist wahrscheinlich nicht das, was Sie wollen, weil -e nur ein Argument nimmt. $1Zeigen Sie mit, dass Ihr Skript nur ein Argument verarbeiten kann.

Es ist wirklich schwierig, mehrere Argumente in dem von Ihnen angegebenen Szenario (mit dem gnome-terminal -e) zum Funktionieren zu bringen, da -enur ein Argument benötigt wird, nämlich eine Shell-Befehlszeichenfolge. Sie müssten Ihre Argumente zu einem zusammenfassen. Der beste und robusteste, aber ziemlich klobige Weg sieht so aus:

gnome-terminal -e "vim $(printf "%q " "$@")"
lhunath
quelle
Vielen Dank dafür! Leider kann ich nur eine Antwort akzeptieren. Ich endete mit "nohup $ @ &> / dev / null &" und "alias wvim = 'launch.sh gnome-terminal -x vim'"
20
Was für eine fantastisch detaillierte und informative Antwort. +1
Teekin
1
@ Hi-Angel Wenn Sie eine interaktive Bash-Shell schließen, werden alle aktiven Jobs von Bash-HUPs ausgeführt. Wenn Sie einen Prozess ausführen, ist er immer noch ein Job, sei es ein Hintergrundprozess. Um es als Job zu entfernen, benutze disown, dann wird der Prozess weiterlaufen, nachdem du die Shell geschlossen hast, da bash es nicht mehr HUPEN wird.
Lhunath
3
Wird nicht verwendet , $*anstatt $@bereits das Problem beheben der einzelnen Strings?
Sjas
2
Was Sie nicht tun können, ist die stdout / stderr / stdin eines Prozesses zu ändern, nachdem Sie ihn gestartet haben. - nicht genau wahr. Verwenden Sie reptyrdafür.
Stefan Seidel
198
nohup cmd &

nohup Löst den Prozess vollständig (daemonisiert ihn)

dsm
quelle
5
Obwohl prägnant ist wertvoll, ist Vollständigkeit mehr wert. Obwohl nohup ein GNU-Coreutil ist, wäre hier eine reine Bash-Antwort (oder ein Hinweis darauf, dass es keine gibt) angebracht. Trotzdem gute Antwort.
Begrenzte Versöhnung
23
nohupignoriert einfach das SIGHUPSignal. Es führt den Prozess normal aus. Keine Dämonisierung.
Nemo
1
@nemo Das bedeutet, dass der Prozess nicht getrennt wird, sondern getrennt wird (und ein Kind von init), wenn die Shell beendet wird ... richtig?
Noldorin
@Noldorin Ja. Wenn Sie SIGHUP ignorieren, das gesendet wird, wenn die Shell beendet wird, wird der untergeordnete Prozess ausgeführt und an init verschoben.
Nemo
@nemo nohup schaltet auch Standard-Ein- / Ausgänge stumm. Folgen Sie mit Verachtung, um sich vollständig zu lösen.
Jiggunjer
60

Wenn Sie verwenden bash, versuchen Sie es ; siehe bash (1) .disown [jobspec]

Ein anderer Ansatz, den Sie ausprobieren können, ist at now. Wenn Sie kein Superuser sind, ist Ihre Nutzungsberechtigung atmöglicherweise eingeschränkt.

Randy Proctor
quelle
"disown" scheint kein interner Bash-Befehl zu sein (auf meinem Computer nicht verfügbar und ich verwende Bash). "nohup", wie Ben angedeutet hat, könnte eine viel bessere (und übliche) Möglichkeit sein, dies zu tun.
1
habe nie daran gedacht "at" zu verwenden, danke für die Idee!
Cadrian
1
atDie Ausführung an jemand anderen zu delegieren, gefällt mir! +1
Ninsuo
1
Als Referenz funktioniert dies zshauch.
Coderer
1
Auch disownscheint nicht die gewünschte Wirkung mit gnome-terminal- disowned Prozessen noch getötet werden , wenn das Terminal beendet. Ich würde gerne wissen warum / wie.
Kyle Strand
38

Als ich diese Antworten las, hatte ich den ersten Eindruck, dass das Ausstellen nohup <command> &ausreichen würde. Als ich zsh im Gnome-Terminal nohup <command> &ausführte , stellte ich fest, dass meine Shell nicht daran gehindert hat, untergeordnete Prozesse beim Beenden zu beenden. Obwohl nohupdies insbesondere bei nicht interaktiven Shells nützlich ist, wird dieses Verhalten nur dann garantiert, wenn der untergeordnete Prozess seinen Handler für das SIGHUPSignal nicht zurücksetzt .

In meinem Fall nohuphätte verhindert werden müssen, dass Aufhängesignale die Anwendung erreichen, aber die untergeordnete Anwendung (in diesem Fall VMWare Player) hat ihren SIGHUPHandler zurückgesetzt. Wenn der Terminalemulator beendet wird, können Ihre Unterprozesse trotzdem abgebrochen werden. Dies kann meines Wissens nur gelöst werden, indem sichergestellt wird, dass der Prozess aus der Auftragstabelle der Shell entfernt wird. Wenn nohupmit einer eingebauten Shell überschrieben wird, wie dies manchmal der Fall ist, kann dies jedoch ausreichen, falls dies nicht der Fall ist ...


disownwird in einem Shell gebautet bash, zshund ksh93,

<command> &
disown

oder

<command> &; disown

wenn Sie Einzeiler bevorzugen. Dies hat den im Allgemeinen wünschenswerten Effekt, dass der Unterprozess aus der Auftragstabelle entfernt wird. Auf diese Weise können Sie den Terminalemulator beenden, ohne den untergeordneten Prozess versehentlich zu signalisieren. Unabhängig davon, wie der SIGHUPHandler aussieht, sollte dies den Prozess Ihres Kindes nicht beenden.

Nach der Deaktivierung ist der Prozess noch ein untergeordnetes Element Ihres Terminal-Emulators (spielen Sie damit, pstreewenn Sie dies in Aktion verfolgen möchten). Nach dem Beenden des Terminal-Emulators sollte er jedoch mit dem Init-Prozess verknüpft sein. Mit anderen Worten, alles ist so, wie es sein sollte und wie Sie es vermutlich wollen.

Was tun, wenn Ihre Shell nicht unterstützt disown? Ich würde nachdrücklich empfehlen, zu einem zu wechseln, der dies tut, aber da diese Option nicht verfügbar ist, haben Sie einige Möglichkeiten.

  1. screenund tmuxkann dieses Problem lösen, aber es sind viel schwerere Lösungen, und ich mag es nicht, sie für eine so einfache Aufgabe ausführen zu müssen. Sie eignen sich viel besser für Situationen, in denen Sie ein tty verwalten möchten, normalerweise auf einem Remotecomputer.
  2. Für viele Benutzer kann es wünschenswert sein, festzustellen, ob Ihre Shell Funktionen wie zsh unterstützt setopt nohup. Hiermit kann festgelegt werden, dass SIGHUPbeim Beenden der Shell keine Nachrichten an die Jobs in der Jobtabelle gesendet werden sollen. Sie können dies entweder direkt vor dem Beenden der Shell anwenden oder der Shell-Konfiguration hinzufügen, als ~/.zshrcob Sie es immer aktivieren möchten.
  3. Finden Sie eine Möglichkeit, die Jobtabelle zu bearbeiten. Ich konnte keinen Weg finden, dies in tcshoder zu tun csh, was etwas störend ist.
  4. Schreiben Sie ein kleines C-Programm zum Abzweigen und exec(). Dies ist eine sehr schlechte Lösung, aber die Quelle sollte nur aus ein paar Dutzend Zeilen bestehen. Sie können dann Befehle als Befehlszeilenargumente an das C-Programm übergeben und so einen prozessspezifischen Eintrag in der Auftragstabelle vermeiden.
Stephen Rosen
quelle
29
  1. nohup $COMMAND &
  2. $COMMAND & disown
  3. setsid command

Ich benutze schon sehr lange Nummer 2, aber Nummer 3 funktioniert genauso gut. Auch disowneine hat nohupFlagge -h, können alle Prozesse disown mit -aund kann alle laufenden Prozesse disown mit -ar.

Die Stummschaltung erfolgt durch $COMMAND &>/dev/null.

Hoffe das hilft!

Mr. Minty Fresh
quelle
Kurz und bündig; danke für diese sehr hilfreiche zusammenfassung!
Sheljohn
Ich kann nicht glauben, dass ich noch Benachrichtigungen für diesen Beitrag bekomme ...
Mr. Minty Fresh
9

Ich denke, Bildschirm könnte Ihr Problem lösen


quelle
9

In tcsh (und möglicherweise auch in anderen Shells) können Sie Klammern verwenden, um den Prozess zu trennen.

Vergleichen Sie dies:

> jobs # shows nothing
> firefox &
> jobs
[1]  + Running                       firefox

Dazu:

> jobs # shows nothing
> (firefox &)
> jobs # still shows nothing
>

Dadurch wird Firefox aus der Jobliste entfernt, es ist jedoch weiterhin mit dem Terminal verbunden. Wenn Sie sich über 'ssh' bei diesem Knoten angemeldet haben, wird der ssh-Prozess beim Versuch, sich abzumelden, immer noch hängen bleiben.

Nathan Fellman
quelle
9

Einfachste und einzig richtige Antwort für bash:

command & disown

Sie müssen den Prozess nicht vom Terminal trennen, sondern von der Shell.

ManuelSchneid3r
quelle
7

Um die Zuordnung der tty-Shell aufzuheben, führen Sie den Befehl über die Sub-Shell aus, z

(Befehl)&

Beim Beenden wird das verwendete Terminal geschlossen, der Prozess ist jedoch noch aktiv.

prüfen -

(sleep 100) & exit

Anderes Terminal öffnen

ps aux | grep sleep

Prozess ist noch am Leben.

jitendra
quelle
Genau das habe ich gebraucht. Ich habe versucht, eine Konsolenverknüpfung für erhabenen Text hinzuzufügen, und sie funktioniert einwandfrei. Am Ende hatte ich Folgendes: ("/ opt / erhabener Text 2 / erhabenerText" $ @) &
Ron E
6

Das Hinterlegen und Vordergrunden eines Jobs ist wahrscheinlich eines der allerersten Dinge, die jeder Unix-Systemadministrator wissen sollte.

So wird es mit bash gemacht:

./script.sh
# suspend process
{ctrl-Z}
# background process
bg
# list all backgrounded jobs
jobs
# bring it back to foreground
fg
Djangofan
quelle
4

Sie können Ihren Befehl mit dem Befehl nohup ausführen. Dadurch wird Ihr Prozess getrennt und die Ausgabe in eine bestimmte Datei umgeleitet. Ich bin mir jedoch nicht sicher, ob dies genau das ist, was Sie benötigen.

Ben
quelle
Ich könnte schwören , ich hatte versucht , nohup vor exec - aber anscheinend nicht richtig, da es wie folgt funktioniert: nohup gnome-terminal -en "vim $ @" &> / dev / null &
2

Try Daemon - sollte bei Ihrem freundlichen Paketmanager erhältlich sein und sich umfassend darum kümmern, sich vom Terminal zu trennen.

ShiDoiSi
quelle
2

Fügen Sie dies einfach in Ihren bashrc / zshrc ein:

detach() {
  "$@" 1>/dev/null 2>/dev/null &; disown
}

Dann können Sie abgelehnte Befehle wie folgt ausführen:

detach gedit ~/.zshrc
B. Branchard
quelle
1

In meinem .bashrc habe ich genau zu diesem Zweck folgende Funktionen:

function run_disowned() {
    "$@" & disown
}

function dos() {
    # run_disowned and silenced

    run_disowned "$@" 1>/dev/null 2>/dev/null
}

Stellen Sie einem Befehl das Präfix voran dos, um ihn vom Terminal getrennt auszuführen.

Die Funktion ist für die Arbeit mit bashund geschrieben zsh.

Mäuse
quelle
1
Ich bin ein wenig verwirrt darüber, dass diese Antwort verwendet eine Funktion in eine andere gewickelt, wenn seine ausreichend nur mit dem Körper wie dieser Funktion zu verwenden: ( "$@" & disown) &> /dev/null. Es macht auch nicht viel Sinn, 1>und 2>, weil Sie verwenden disown, was bedeutet, dass Sie bash verwenden, und in bash können Sie einfach tun &>, um sowohl stdout als auch stderr umzuleiten
Sergiy Kolodyazhnyy
Ich habe es als zwei Funktionen, weil (1) ich denke, es ist einfacher, auf diese Weise zu lesen, und (2) ich brauche die run_disownedFunktionalität an anderen Stellen in meinen Punktedateien. Da hast du &>natürlich recht .
mic_e
0

Ich habe unter Mac OS X festgestellt, dass ich sowohl nohup als auch disown verwenden muss, um sicherzustellen, dass der untergeordnete Prozess nicht mit dem Terminal abgerissen wird.

Aaron
quelle
0

Ich benutze das folgende Skript, um dies zu tun. Es stoppt den Druckvorgang auf dem Terminal, löst sich mit nohupund beendet sich mit dem Rückgabestatus, wenn der Befehl innerhalb von beendet wird TIMEOUT.

#!/bin/bash

TIMEOUT=0.1

CMD=( "$@" )
#Could have some shortcuts here, e.g. replace "somefile.c" with "gedit somefile.c"

#use nohup to run the command, suppressing its output and allowing the terminal to be closed
#also send nohup's output to /dev/null, supressing nohup.out
#run nohup in the background so this script doesn't block
#print the command for debugging and to see bash variable expansion
printf "%q " "${CMD[@]}"
echo
nohup "${CMD[@]}" >/dev/null 2>&1 &
NOHUP_PID=$!

#kill this script after a short time, exiting with success status - command is still running
#this is needed as there is no timeout argument for `wait` below
MY_PID=$$
trap "exit 0" SIGINT SIGTERM
sleep $TIMEOUT && kill $MY_PID 2>/dev/null & #ignore "No such process" error if this exits normally

#if the command finishes before the above timeout, everything may be just fine or there could have been an error
wait $NOHUP_PID
NOHUP_STATUS=$?
#print an error if there was any. most commonly, there was a typo in the command
[ $NOHUP_STATUS != 0 ] && echo "Error: $CMD"
#return the exit status of nohup, whatever it was
exit $NOHUP_STATUS

Anwendungsbeispiel:

>>> run false
false
Error: false
>>> echo $?
1
>>> run true
true
>>> run sleep 10
sleep 10
>>>
jozxyqk
quelle
0

sudo apt install ucommon-utils

pdetach command

Los geht's :)

d4rk4ng31
quelle
-1

Viele Antworten schlugen vor, nohup zu verwenden . Ich würde eher empfehlen, pm2 zu verwenden . Die Verwendung von pm2 über nohup bietet viele Vorteile, z. B. die Aufrechterhaltung des Betriebs der Anwendung, die Verwaltung von Protokolldateien für die Anwendung und viele weitere Funktionen. Weitere Informationen finden Sie hier .

Um pm2 zu installieren, müssen Sie npm herunterladen . Für Debian-basiertes System

sudo apt-get install npm

und für Redhat

sudo yum install npm

Oder folgen Sie diesen Anweisungen . Nach der Installation von npm benutze es, um pm2 zu installieren

npm install pm2@latest -g

Sobald es fertig ist, können Sie Ihre Anwendung durch starten

$ pm2 start app.js              # Start, Daemonize and auto-restart application (Node)
$ pm2 start app.py              # Start, Daemonize and auto-restart application (Python)

Verwenden Sie zur Prozessüberwachung folgende Befehle:

$ pm2 list                      # List all processes started with PM2
$ pm2 monit                     # Display memory and cpu usage of each app
$ pm2 show [app-name]           # Show all informations about application

Verwalten Sie Prozesse mithilfe des App-Namens oder der Prozess-ID oder verwalten Sie alle Prozesse zusammen:

$ pm2 stop     <app_name|id|'all'|json_conf>
$ pm2 restart  <app_name|id|'all'|json_conf>
$ pm2 delete   <app_name|id|'all'|json_conf>

Protokolldateien finden Sie in

$HOME/.pm2/logs #contain all applications logs
Drecksack
quelle
1
Die Verwendung einer NodeJS-Anwendung (im Gegensatz zu einem kleinen und robusten Befehl wie nohup) zur Steuerung von Unix-Prozessen scheint ... wirklich übertrieben und ehrlich, ziemlich seltsam. Ich würde Monit verwenden, wenn Sie die Neustart-Funktionalität benötigen.
Sergio
Bei Sergio haben Sie die Wahl, eine benachteiligte Anwendung zu verwenden.
Haccks
In diesem Jahr wurden mehrere Releases veröffentlicht (eines vor 4 Tagen), daher verstehe ich nicht, wie / warum Sie monit für eine veraltete Anwendung halten. @see mmonit.com/monit/changes
Sergio
Ich habe über Nohup gesprochen.
haccks
1
nohupist ein einfacher POSIX-Standardbefehl, daher die gleiche Bemerkung: auf keinen Fall veraltet. @see unix.com/man-page/posix/1p/nohup
Sergio
-1

Wenn Sie lediglich eine Befehlszeilenanwendung starten möchten, ohne das Terminalfenster dabei zu belassen, können Sie versuchen, die Anwendung nach dem Starten des Terminals mit Alt-F2 auszuführen.

MattKelly
quelle