Come posso eseguire un comando che sopravviverà alla chiusura del terminale?


313

A volte voglio iniziare un processo e non pensarci più. Se lo avvio dalla riga di comando, in questo modo:

redshift

Non riesco a chiudere il terminale, o ucciderà il processo. Posso eseguire un comando in modo tale da poter chiudere il terminale senza interrompere il processo?


4
Non è un'installazione predefinita su tutte le distro, ma lo schermo è tuo amico: en.wikipedia.org/wiki/GNU_Screen
Zayne S Halsall

A chiunque si trovi di fronte allo stesso problema: ricorda che anche se digiti yourExecutable &e le uscite continuano a comparire sullo schermo e Ctrl+Cnon sembrano fermare nulla, digita alla cieca disown;e premi Enteranche se lo schermo scorre con le uscite e non riesci a vedere cosa stai scrivendo. Il processo verrà ignorato e sarai in grado di chiudere il terminale senza che il processo muoia.
Nav

È possibile utilizzare il multiplexer dello schermo come tmux . È disponibile tramite apt-get su macchine Ubuntu
Himanshu

Risposte:


311

Uno dei seguenti 2 dovrebbe funzionare:

$ nohup redshift &

o

$ redshift &
$ disown

Vedere di seguito per ulteriori informazioni su come funziona:


5
Il secondo ( redshift & disown) ha funzionato per me su Ubuntu 10.10. Sembra funzionare bene mettendo tutto su una linea. C'è qualche motivo per cui non dovrei farlo?
Matteo,

4
@Matthew Anche il primo dovrebbe funzionare bene, semplicemente non ha lo sfondo del secondo (forse lo vuoi, nohup redshift &quindi fa lo sfondo). E mettere la seconda su una riga va bene, anche se di solito ti separi con ;( redshift &; disown)
Michael Mrozek

10
@Michael: Entrambi ;e &sono separatori di comando e hanno uguale precedenza. L'unica differenza è l'esecuzione sincrona o asincrona (rispettivamente). Non è necessario utilizzare &;preferibilmente solo &(funziona, ma è un po 'ridondante).
Chris Johnsen,

4
buona risposta, si potrebbe aggiungere che sarebbe una buona idea reindirizzare stdout e stderr in modo che il terminale non venga spammato con output di debug
Kim

12
Inoltre, redshift &!rinnegherà immediatamente il redshift.

143

Se il tuo programma è già in esecuzione , puoi metterlo in pausa Ctrl-Z, trascinarlo in background bge quindi disown, in questo modo:

$ sleep 1000
^Z
[1]+  Stopped                 sleep 1000
$ bg
$ disown
$ exit

3
dopo aver rinnegato come posso leggere di nuovo lo stdout del processo in esecuzione?
Necktwi,


1
Questo non ha funzionato per me per qualche motivo (centos)
Ian

Come terminare il processo dopo questa procedura?
Palak Darji,

2
@necktwi disownnon disconnette stdout o stderr. Tuttavia nohup, come >/dev/null(disconnessione standard out), 2>/dev/null(disconnessione errore standard). It ( disown) disconnette il controllo del lavoro.
ctrl-alt-delor,

45

La buona risposta è già pubblicata da @StevenD, ma penso che ciò potrebbe chiarire un po 'di più.

Il motivo per cui il processo viene interrotto al termine del terminale è che il processo avviato è un processo figlio del terminale. Una volta chiuso il terminale, questo ucciderà anche questi processi figlio. Puoi vedere l'albero dei processi con pstree, ad esempio quando kate &esegui in Konsole:

init-+
     ├─konsole─┬─bash─┬─kate───2*[{kate}]
     │         │      └─pstree
     │         └─2*[{konsole}]

Per staccare il kateprocesso da konsolequando si termina konsole, utilizzare nohupcon il comando, in questo modo:

nohup kate &

Dopo la chiusura konsole, pstreesarà simile al seguente:

init-+
     |-kate---2*[{kate}]

e katesopravviverà. :)

Un'alternativa sta usando screen/ tmux/ byobu, che manterrà la shell in esecuzione, indipendentemente dal terminale.


Ho avuto problemi con i metodi rinnegati. Questo funziona attualmente per me, quindi votazione. Mi piace anche perché riesco a vedere -f nohup.out per vedere cosa sta succedendo, ma non preoccuparmi del fallimento della mia sessione
Ian

27

È possibile eseguire il processo in questo modo nel terminale

setsid process

Questo eseguirà il programma in una nuova sessione. Come spiegato http://hanoo.org/index.php?article=run-program-in-new-session-linux


1
Quali sono i vantaggi di setsid rispetto a nohup?
itsbruce

1
1) Non stampa un messaggio fastidioso nohup.out. 2) Non rimane nell'elenco dei lavori della shell, quindi non ingombra l'output di jobs.
Mikel,

Questa è l'unica soluzione che ha funzionato con lo script che gira in lxterminal, avvia pcmanfm ed esce (con setsid il terminale può chiudersi mentre pcmanfm continua a funzionare). Grazie mille!
desgua

9

Sebbene tutti i suggerimenti funzionino bene, ho scoperto che la mia alternativa è usare screen, un programma che imposta un terminale virtuale sullo schermo.

Potresti considerare di iniziare con . Lo schermo può essere installato praticamente su tutti i derivati ​​Linux e Unix. Colpire + e (lettere minuscole) inizierà una seconda sessione. Ciò consentirebbe di passare avanti e indietro tra la sessione iniziale premendo + e o la sessione più recente premendo + escreen -S session_nameCtrlACCtrlA0CtrlA1 . Puoi avere fino a dieci sessioni in un terminale. Avviavo una sessione di lavoro, tornavo a casa, ssh nella mia macchina di lavoro e poi invocavo . Questo ti riconnetterà a quella sessione remota.screen -d -R session_name


screen -d -m commandlo avvierò in una schermata già staccata: ~# screen -d -m top ~# screen -ls There is a screen on: 10803..Server-station (Detached) 1 Socket in /root/.screen. ~# screen -x .... e ci sei.
Dr. Alexander,

7

Il modo solo shell di fare tutto questo è chiudere stdin e in background il comando:

command <&- & 

Quindi non si chiuderà quando si esce dalla shell. Il reindirizzamento di stdout è una cosa facoltativa da fare.

Lo svantaggio è che non puoi farlo dopo il fatto.


Ho provato su Ubuntu. Anche il terminale di uccisione ha chiuso il processo avviato. Qualche idea sul perché questo potrebbe essere il caso?
Ashok Koyi,

7

Ho una sceneggiatura per:

  • Esegui comandi arbitrari in background

  • Impedisci loro di essere uccisi con la finestra del terminale

  • Sopprime il loro output

  • Gestisce lo stato di uscita

Lo uso principalmente per gedit, ecc. evince, inkscapeChe hanno tutti un output terminale fastidioso. Se il comando termina prima TIMEOUT, viene restituito lo stato di uscita di nohup anziché zero.

#!/bin/bash

TIMEOUT=0.1

#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
nohup "${@}" >/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 ${@}"
#return the exit status of nohup, whatever it was
exit $NOHUP_STATUS

esempi ...

>>> run true && echo success || echo fail
success
>>> run false && echo success || echo fail
Error false
fail
>>> run sleep 1000 && echo success || echo fail
success
>>> run notfound && echo success || echo fail
Error notfound
fail

7

Preferisco:

(Nome dell'applicazione &)

per esempio: linux@linux-desktop:~$ (chromium-browser &)

Assicurati di usare la parentesi quando digita il comando!


1
Chiudere il terminale ucciderà il processo , cosa che esattamente ciò che OP (e io, venendo qui) vuole evitare
gromit190

1
Probabilmente hai un comando rapido che ho usato nella mia risposta senza parentesi, in tal caso la chiusura del terminale ucciderà il processo, altrimenti NON accadrà. Ho già modificato la soluzione sopra per chiarire.
Go

lavoro per me, tnx
noadev

Mi chiedo perché questo non abbia ottenuto più voti. nohupimpedisce qualsiasi output di tty e in realtà volevo solo reindirizzare l'output su un file e questo mi ha impedito, quindi questa è la soluzione migliore per me.
redanimalwar,

4

È possibile impostare un processo (PID) per non ricevere un segnale HUP al logout e alla chiusura della sessione del terminale. Utilizzare il comando seguente:

nohup -p PID

3

Probabilmente simile alla risposta offerta da apolinsky , utilizzo una variante su screen. Il comando vanilla è così

screen bash -c 'long_running_command_here; echo; read -p "ALL DONE:"'

La sessione può essere disconnessa Ctrl ACtrl De ricollegata nel caso semplice con screen -r. Ho questo avvolto in uno script chiamato sessionche vive nel mio PATHpronto per un comodo accesso:

#!/bin/bash
#
if screen -ls | awk '$1 ~ /^[1-9][0-9]*\.'"$1"'/' >/dev/null
then
    echo "WARNING: session is already running (reattach with 'screen -r $1')" >&2
else
    exec screen -S "$1" bash -c "$@; echo; echo '--------------------'; read -p 'ALL DONE (Enter to exit):'"
    echo "ERROR: 'screen' is not installed on this system" >&2
fi
exit 1

Funziona solo quando sai in anticipo che vuoi disconnettere un programma. Non prevede la disconnessione di un programma già in esecuzione .


2

Analogamente ad altre risposte precedentemente pubblicate, è possibile trasferire un processo in esecuzione per utilizzare retrospettivamente lo "schermo" grazie a reptyr e quindi chiudere il terminale. I passaggi sono descritti in questo post . I passi da compiere sono:

  1. Sospendi il processo
  2. Riprendi il processo in background
  3. Nega il processo
  4. Avvia una sessione schermo
  5. Trova il PID del processo
  6. Utilizzare reptyr per assumere il controllo del processo
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.