Come posso staccare completamente un processo dal Terminale?


304

Uso Tilda (terminale a discesa) su Ubuntu come il mio "comando centrale" - praticamente come gli altri potrebbero usare GNOME Do, Quicksilver o Launchy.

Tuttavia, sto lottando su come staccare completamente un processo (ad esempio Firefox) dal terminale da cui è stato avviato, ovvero impedire che tale processo (non) figlio

  • viene chiuso alla chiusura del terminale di origine
  • "inquina" il terminale di origine tramite STDOUT / STDERR

Ad esempio, per avviare Vim in una finestra del terminale "corretta", ho provato un semplice script come il seguente:

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

Tuttavia, ciò causa ancora inquinamento (inoltre, il passaggio di un nome file non sembra funzionare).


1
Anche questa è una buona domanda. Penso che sia giusto considerare Bash un linguaggio di programmazione - anche se in effetti lo scopo di questa domanda è probabilmente più sul lato del sysadmin ...

Questo è un duplicato di questa domanda stackoverflow.com/questions/285015/…
Dana the Sane


Il tuo caso d'uso non descrive di per sé il distacco completo.
jiggunjer,

Risposte:


344

Prima di tutto; una volta che hai avviato un processo, puoi metterlo in background fermandolo prima (premi Ctrl- Z) e poi digitando bgper farlo riprendere in background. Ora è un "lavoro" e i suoi stdout/ stderr/ stdinsono ancora connessi al tuo terminale.

È possibile avviare immediatamente un processo come sfondo aggiungendo un "&" alla fine:

firefox &

Per eseguirlo in background messo a tacere, utilizzare questo:

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

Alcune informazioni aggiuntive:

nohupè un programma che puoi usare per eseguire la tua applicazione in modo tale che il suo stdout / stderr possa essere inviato a un file e tale che la chiusura dello script genitore non SIGHUP il figlio. Tuttavia, è necessario aver avuto la lungimiranza di averlo usato prima di avviare l'applicazione. A causa del modo in cui nohupfunziona, non puoi semplicemente applicarlo a un processo in esecuzione .

disownè un built-in bash che rimuove un lavoro shell dall'elenco dei lavori della shell. Ciò che sostanzialmente significa che non puoi più usarlo fg, bgma soprattutto, quando chiudi la shell non si bloccherà o invierà più SIGHUPa quel bambino. Diversamente nohup, disownviene utilizzato dopo l'avvio e il background del processo.

Quello che non puoi fare è cambiare lo stdout / stderr / stdin di un processo dopo averlo lanciato. Almeno non dalla shell. Se avvii il tuo processo e dici che il suo stdout è il tuo terminale (che è quello che fai di default), quel processo è configurato per l'output sul tuo terminale. La tua shell non ha rapporti commerciali con la configurazione FD dei processi, che è puramente qualcosa che il processo stesso gestisce. Il processo stesso può decidere se chiudere o meno lo stdout / stderr / stdin, ma non è possibile utilizzare la shell per forzarlo.

Per gestire l'output di un processo in background, hai molte opzioni dagli script, "nohup" probabilmente è il primo a venire in mente. Ma per i processi interattivi si avvia ma si è dimenticati del silenzio ( firefox < /dev/null &>/dev/null &) non si può fare molto, davvero.

Ti consiglio di ottenere GNU screen. Con lo schermo puoi semplicemente chiudere la shell in esecuzione quando l'output del processo diventa un problema e aprirne uno nuovo ( ^Ac).


Oh, a proposito, non usare " $@" dove lo stai usando.

$@significa, $1, $2, $3..., atta a rendere il vostro comando in:

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

Probabilmente non è quello che vuoi perché prende solo un argomento. Usa $1per mostrare che il tuo script può gestire solo un argomento.

È davvero difficile far funzionare correttamente più argomenti nello scenario che hai fornito (con il gnome-terminal -e) perché -eaccetta solo un argomento, che è una stringa di comandi della shell. Dovresti codificare i tuoi argomenti in uno solo. Il modo migliore e più robusto, ma piuttosto rozzo, è così:

gnome-terminal -e "vim $(printf "%q " "$@")"

Grazie mille per questo! Purtroppo posso accettare solo una risposta. Ho finito con "nohup $ @ &> / dev / null &" e "alias wvim = 'launch.sh gnome-terminal -x vim'"

20
Che risposta straordinariamente dettagliata e istruttiva. +1
Teekin,

1
@ Hi-Angel quando chiudi una shell bash interattiva, bash HUPs tutti i lavori attivi. Quando ^ Z e bg un processo è ancora un lavoro, sia esso di sottofondo. Per rimuoverlo come lavoro, utilizzare disown, quindi il processo continuerà a vivere dopo aver chiuso la shell poiché bash non lo farà più.
lhunath,

3
Non utilizzerai $*invece di $@risolvere il problema delle stringhe separate già?
sjas,

2
Quello che non puoi fare è cambiare lo stdout / stderr / stdin di un processo dopo averlo lanciato. - non esattamente vero. Usa reptyrper questo.
Stefan Seidel,

198
nohup cmd &

nohup stacca completamente il processo (lo demonizza)


5
Sebbene il succinto sia prezioso, la completezza è più preziosa. Sebbene nohup sia un coreutil GNU, una risposta solo bash (o nota sul fatto che non ce n'è uno) qui sarebbe appropriata. Buona risposta comunque.
Espiazione limitata il

23
nohupignora semplicemente il SIGHUPsegnale. Esegue il processo normalmente. Nessuna demonizzazione.
nemo

1
@nemo Il che significa che il processo non è staccato, ma sarebbe staccato (e figlio di init) se la shell uscisse ... giusto?
Noldorin

@Noldorin Sì. Ignorare SIGHUP, che viene inviato al termine della shell, lascerà il processo figlio in esecuzione e verrà trasferito in init.
nemo

@nemo nohup mette a tacere anche gli ingressi / le uscite standard. Seguire con rinnegamento per staccare completamente.
jiggunjer,

60

Se stai usando bash, prova ; vedi bash (1) .disown [jobspec]

Un altro approccio che puoi provare è at now. Se non sei un superutente, il tuo permesso di utilizzo atpotrebbe essere limitato.


"disown" non sembra essere un comando bash interno (non disponibile sulla mia macchina e utilizzo bash). "Nohup", come ha suggerito Ben, potrebbe essere un modo molto migliore (e standard) di farlo.

1
mai pensato di usare "at", grazie per l'idea!
cadrian,

1
atdelegare l'esecuzione a qualcun altro, mi piace! +1
Ninsuo,

1
Come punto di riferimento, anche questo funziona zsh.
Coderer,

1
Inoltre, disownnon sembra avere l'effetto desiderato con gnome-terminal- i disownprocessi ed vengono comunque interrotti quando il terminale esce. Mi piacerebbe sapere perché / come.
Kyle Strand,

38

Leggendo queste risposte, ho avuto l'impressione iniziale che l'emissione nohup <command> &sarebbe stata sufficiente. Eseguendo zsh in gnome-terminal, ho scoperto che nohup <command> &non impediva alla mia shell di uccidere i processi figlio all'uscita. Sebbene nohupsia utile, specialmente con shell non interattive, garantisce questo comportamento solo se il processo figlio non reimposta il gestore per il SIGHUPsegnale.

Nel mio caso, nohupavrei dovuto impedire ai segnali di riaggancio di raggiungere l'applicazione, ma l'applicazione figlio (in questo caso VMWare Player) stava ripristinando il suo SIGHUPgestore. Di conseguenza, quando termina l'emulatore di terminale, è possibile che i processi secondari vengano comunque interrotti. Per quanto ne so, questo può essere risolto solo assicurando che il processo venga rimosso dalla tabella dei lavori della shell. Se nohupviene sovrascritto con una shell incorporata, come talvolta accade, ciò può essere sufficiente, tuttavia, nel caso in cui non sia ...


disownè un guscio in builtin bash, zshe ksh93,

<command> &
disown

o

<command> &; disown

se preferisci una linea. Ciò ha l'effetto generalmente desiderabile di rimuovere il sottoprocesso dalla tabella dei lavori. Ciò consente di uscire dall'emulatore di terminale senza segnalare inavvertitamente il processo figlio. Indipendentemente SIGHUPdall'aspetto del gestore, questo non dovrebbe uccidere il processo figlio.

Dopo il rinvio, il processo è ancora figlio del tuo emulatore di terminale (gioca con pstreese vuoi vederlo in azione), ma dopo l'uscita dell'emulatore di terminale, dovresti vederlo allegato al processo di init. In altre parole, tutto è come dovrebbe essere e come presumibilmente vuoi che sia.

Cosa fare se la shell non supporta disown? Consiglio vivamente di passare a uno che lo fa, ma in assenza di tale opzione, hai alcune scelte.

  1. screene tmuxpuò risolvere questo problema, ma sono soluzioni di peso molto più pesanti e non mi piace doverle eseguire per un compito così semplice. Sono molto più adatti a situazioni in cui si desidera mantenere un tty, in genere su una macchina remota.
  2. Per molti utenti, potrebbe essere desiderabile vedere se la tua shell supporta una funzionalità come quella di zsh setopt nohup. Questo può essere usato per specificare che SIGHUPnon dovrebbe essere inviato ai lavori nella tabella dei lavori quando la shell esce. Puoi applicarlo poco prima di uscire dalla shell, oppure aggiungerlo alla configurazione della shell come ~/.zshrcse lo volessi sempre.
  3. Trova un modo per modificare la tabella dei lavori. Non sono riuscito a trovare un modo per farlo in tcsho csh, il che è alquanto inquietante.
  4. Scrivi un piccolo programma C per fork e exec(). Questa è una soluzione molto scadente, ma la fonte dovrebbe consistere solo in una dozzina di righe. È quindi possibile passare i comandi come argomenti della riga di comando al programma C, evitando così una voce specifica del processo nella tabella dei lavori.

29
  1. nohup $COMMAND &
  2. $COMMAND & disown
  3. setsid command

Sto usando il numero 2 da molto tempo, ma il numero 3 funziona altrettanto bene. Inoltre, disownha un nohupflag di -h, può rinnegare tutti i processi con -ae può rinnegare tutti i processi in esecuzione con -ar.

Il silenzio è realizzato da $COMMAND &>/dev/null.

Spero che sia di aiuto!


Corto e dolce; grazie per questo riepilogo molto utile!
Sheljohn, il

Non riesco a credere di ricevere ancora notifiche per questo post ...
Mr. Minty Fresh

9

Penso che lo schermo potrebbe risolvere il tuo problema


9

in tcsh (e forse anche in altre shell), puoi usare le parentesi per staccare il processo.

Confronta questo:

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

A questo:

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

Ciò rimuove firefox dall'elenco dei lavori, ma è ancora legato al terminale; se si è effettuato l'accesso a questo nodo tramite 'ssh', il tentativo di disconnettersi bloccherà comunque il processo ssh.


9

La risposta più semplice e corretta per bash:

command & disown

Non è necessario staccare il processo dal terminale, ma dalla shell.


7

Per dissociare la shell tty, eseguire il comando tramite la shell secondaria per es

(comando)&

Quando si esce dal terminale usato chiuso ma il processo è ancora attivo.

dai un'occhiata -

(sleep 100) & exit

Apri un altro terminale

ps aux | grep sleep

Il processo è ancora vivo.


Questo è esattamente ciò di cui avevo bisogno. Stavo tentando di aggiungere una scorciatoia da console per il testo sublime e funziona perfettamente, ecco cosa ho finito con: ("/ opt / Sublime Text 2 / sublime_text" $ @) &
Ron E

5

Lo sfondo e il primo piano di un lavoro è probabilmente una delle primissime cose che ogni amministratore di sistema Unix dovrebbe sapere.

Ecco come si fa con bash:

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

4

Puoi eseguire il tuo comando usando il comando nohup, questo scollega il tuo processo e reindirizza gli output su un determinato file ... ma non sono sicuro che sia esattamente quello che ti serve ..


Potrei giurare di aver provato nohup prima di usare exec - ma apparentemente non correttamente, dato che funziona così: nohup gnome-terminal -e "vim $ @" &> / dev / null &

2

Prova il demone : dovrebbe essere disponibile presso il tuo amichevole gestore di pacchetti e prendersi cura di tutti i modi per dissociarsi dal terminale.


2

Basta aggiungere questo nel tuo bashrc / zshrc:

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

Quindi è possibile eseguire comandi sconosciuti in questo modo:

detach gedit ~/.zshrc

1

Nel mio .bashrc, ho queste funzioni proprio per quello scopo:

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

function dos() {
    # run_disowned and silenced

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

Prefisso un comando con dosper eseguirlo distaccato dal terminale.

La funzione è scritta per funzionare con bashe zsh.


1
Sto un po 'confuso sul motivo per cui questa risposta utilizza una funzione avvolto in un altro, quando la sua sufficiente utilizzare solo una funzione con corpo come questo: ( "$@" & disown) &> /dev/null. Non ha molto senso usare 1>e 2>, poiché stai usando disown, il che significa che stai usando bash, e in bash puoi semplicemente fare il &>reindirizzamento di stdout e stderr
Sergiy Kolodyazhnyy

L'ho come due funzioni perché (1) penso che sia più facile da leggere in questo modo, e (2) ho bisogno della run_disownedfunzionalità in altri punti nei miei dotfile. Hai ragione sulla &>cosa, ovviamente.
mic_e

0

Ho scoperto su Mac OS X che ho bisogno di usare sia Nohup che DISDOW per assicurarmi che il processo figlio non venga abbattuto con il terminale.


0

Per fare questo uso il seguente script. Arresta la stampa del processo sul terminale, si stacca con nohuped esce con lo stato di ritorno se il comando termina all'interno di 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

Esempio di utilizzo:

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

0

sudo apt install ucommon-utils

pdetach command

Ecco qua :)


-1

Molte risposte suggerite usando nohup . Preferirei suggerire di usare pm2 . L'uso di pm2 su nohup ha molti vantaggi, come mantenere attiva l'applicazione, mantenere i file di registro per l'applicazione e molte altre funzionalità. Per maggiori dettagli controlla questo .

Per installare pm2 è necessario scaricare npm . Per sistema basato su Debian

sudo apt-get install npm

e per Redhat

sudo yum install npm

Oppure puoi seguire queste istruzioni . Dopo aver installato npm, usalo per installare pm2

npm install pm2@latest -g

Una volta terminato, puoi avviare l'applicazione entro

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

Per il monitoraggio del processo utilizzare i seguenti comandi:

$ 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

Gestisci i processi utilizzando il nome dell'app o l'ID processo o gestisci tutti i processi insieme:

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

I file di registro sono disponibili in

$HOME/.pm2/logs #contain all applications logs

1
L'uso di un'applicazione NodeJS (rispetto a un comando piccolo e robusto come nohup) per controllare i processi unix sembra ... davvero eccessivo, e ad essere sincero, piuttosto strano. Userei monit se hai bisogno della funzionalità di riavvio.
Sergio,

@Sergio è la tua scelta di utilizzare un'applicazione deprecata.
Hawcks,

Quest'anno sono state rilasciate diverse versioni (una 4 giorni fa), quindi non vedo come / perché potresti pensare che Monit sia un'applicazione obsoleta. @vedi mmonit.com/monit/changes
Sergio,

Stavo parlando di nohup.
Hawcks

1
nohupè un semplice comando POSIX standard, quindi stessa osservazione: in nessun modo è obsoleto. @vedi unix.com/man-page/posix/1p/nohup
Sergio,

-1

Se il tuo obiettivo è semplicemente lanciare un'applicazione da riga di comando senza mantenere la finestra del terminale, allora potresti provare a eseguire l'applicazione dopo aver avviato il terminale con alt-F2.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.