Come posso mettere un processo già in esecuzione sotto nohup?


940

Ho un processo che è già in esecuzione da molto tempo e non voglio interromperlo.

Come posso metterlo sotto nohup (ovvero, come faccio a farlo continuare anche se chiudo il terminale?)


29
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

Risposte:


1367

Usando il Job Control di bash per inviare il processo in background:

  1. Ctrl+ Zper interrompere (mettere in pausa) il programma e tornare alla shell.
  2. bg per eseguirlo in background.
  3. disown -h [job-spec]dove [job-spec] è il numero del lavoro (come %1per il primo lavoro in esecuzione; trova il tuo numero con il jobscomando) in modo che il lavoro non venga interrotto alla chiusura del terminale.

38
Poiché la domanda era come "metterlo sotto nohup", disown -hforse è la risposta più esatta: "fare in modo che il disconnessione si comporti più come un nohup (cioè i lavori rimarranno nell'albero del processo della shell corrente fino a quando non si esce dalla shell) Ciò consente di vedere tutti i lavori avviati da questa shell ". (da [ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/… )
Dr. Jan-Philip Gehrcke,

8
Come posso recuperare il lavoro in seguito? Posso vederlo in esecuzione usando ps -e.
Paulo Casaretto,

26
Non è possibile visualizzare l'output di un lavoro dopo un disown, disown rende un processo un demone, il che significa che l'input / output standard viene reindirizzato a / dev / null. Quindi, se hai intenzione di rinnegare un lavoro, è meglio avviarlo accedendo a un file, ad esempiomy_job_command | tee my_job.log
rustyx

8
è possibile in qualche modo fare qualcosa come 'my_job_command | tee my_job.log ' dopo che il comando è già in esecuzione?
Arod

23
disowndissocia qualsiasi tubo dal processo. Per ricollegare i tubi, utilizzare gdbcome descritto in questa discussione . Più specificamente, questo post .
mbrownnyc,

185

Supponiamo che anche per qualche motivo Ctrl+ Znon psfunzioni , vai su un altro terminale, trova l'id di processo (usando ) ed esegui:

kill -SIGSTOP PID 
kill -SIGCONT PID

SIGSTOPsospenderà il processo e SIGCONTriprenderà il processo, in background. Quindi ora chiudere entrambi i terminali non interromperà il processo.


10
Sì, questo è un problema con il sistema operativo, kill non funziona con Cygwin su Windows.
Pungs,

6
Molto utile anche se il lavoro viene avviato da un'altra sessione SSH.
Amir Ali Akbari,

5
Ricordati di fare disown %1il primo terminale prima di chiuderlo.
fred

1
Questo è utile da quando ho avviato un'interfaccia grafica con una console (nel mio caso sono partito da Konsole kwindopo un crash senza pensare alle conseguenze). Quindi se avessi fermato Kwin, tutto sarebbe congelato e non avrei avuto possibilità di correre bg!
Michele,

@fred Non l'ho fatto e sembrava continuare a correre. Possibile o ho colpito il PID sbagliato?
Nessuno

91

Il comando per separare un lavoro in esecuzione dalla shell (= lo rende nohup) è disownun comando shell di base.

Da bash-manpage (man bash):

disown [-ar] [-h] [jobspec ...]

Senza opzioni, ogni jobspec viene rimosso dalla tabella dei lavori attivi. Se viene fornita l'opzione -h, ogni jobspec non viene rimosso dalla tabella, ma è contrassegnato in modo che SIGHUP non venga inviato al lavoro se la shell riceve un SIGHUP. Se non è presente jobspec e non viene fornita né l'opzione -a né -r, viene utilizzato il lavoro corrente. Se non viene fornito jobspec, l'opzione -a significa rimuovere o contrassegnare tutti i lavori; l'opzione -r senza argomento jobspec limita l'operazione ai lavori in esecuzione. Il valore restituito è 0 a meno che un jobspec non specifichi un lavoro valido.

Ciò significa che è semplice

disown -a

rimuoverà tutti i lavori dalla tabella dei lavori e li renderà nohup


9
disown -arimuove tutti i lavori. Un semplice disownrimuove solo il lavoro corrente. Come dice la pagina man nella risposta.
Rune Schjellerup Philosof,

73

Queste sono buone risposte sopra, volevo solo aggiungere un chiarimento:

Non puoi fare disownun pid o un processo, sei disownun lavoro, e questa è una distinzione importante.

Un lavoro è qualcosa che è una nozione di un processo che è collegato a una shell, quindi è necessario gettare il lavoro in background (non sospenderlo) e quindi rinnegarlo.

Problema:

%  jobs
[1]  running java 
[2]  suspended vi
%  disown %1

Vedi http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/ per una discussione più dettagliata di Unix Job Control.


48

Sfortunatamente disownè specifico per bash e non è disponibile in tutte le shell.

Alcune versioni di Unix (ad es. AIX e Solaris) hanno un'opzione sul nohupcomando stesso che può essere applicata a un processo in esecuzione:

nohup -p pid

Vedi http://en.wikipedia.org/wiki/Nohup


Solo per AIXe Solaris. "Le versioni AIX e Solaris di nohup hanno un'opzione -p che modifica un processo in esecuzione per ignorare i futuri segnali SIGHUP. A differenza del sopra descritto difetto di bash, nohup -p accetta gli ID di processo.". Fonte
AlikElzin-Kilaka,

27

La risposta di Node è davvero eccezionale, ma ha lasciato aperta la domanda su come ottenere reindirizzamento di stdout e stderr. Ho trovato una soluzione su Unix e Linux , ma non è completa. Vorrei unire queste due soluzioni. Ecco qui:

Per il mio test ho realizzato un piccolo script bash chiamato loop.sh, che stampa il pid di se stesso con un minuto di sonno in un ciclo infinito.

$./loop.sh

Ora ottieni il PID di questo processo in qualche modo. Di solito ps -C loop.shè abbastanza buono, ma è stampato nel mio caso.

Ora possiamo passare a un altro terminale (o premere ^ Z e nello stesso terminale). Ora gdbdovrebbe essere collegato a questo processo.

$ gdb -p <PID>

Questo interrompe lo script (se in esecuzione). Il suo stato può essere verificato da ps -f <PID>, dove il STATcampo è 'T +' (o nel caso di ^ Z 'T'), che significa (man ps (1))

    T Stopped, either by a job control signal or because it is being traced
    + is in the foreground process group

(gdb) call close(1)
$1 = 0

Chiudi (1) restituisce zero in caso di successo.

(gdb) call open("loop.out", 01102, 0600)
$6 = 1

Apri (1) restituisce il nuovo descrittore di file in caso di successo.

Questa apertura è uguale a open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR). Invece di O_RDWR O_WRONLYpotrebbe essere applicato, ma /usr/sbin/lsofdice 'u' per tutti i gestori di file std * ( FDcolonna), che è O_RDWR.

Ho controllato i valori nel file di intestazione /usr/include/bits/fcntl.h.

Il file di output potrebbe essere aperto O_APPEND, come nohupfarebbe, ma questo non è suggerito da man open(2), a causa di possibili problemi di NFS.

Se otteniamo -1 come valore di ritorno, call perror("")stampa il messaggio di errore. Se abbiamo bisogno dell'errno, usa il p errnocomando gdb.

Ora possiamo controllare il file appena reindirizzato. /usr/sbin/lsof -p <PID>stampe:

loop.sh <PID> truey    1u   REG   0,26        0 15008411 /home/truey/loop.out

Se vogliamo, possiamo reindirizzare stderr a un altro file, se vogliamo usare call close(2)e call open(...)usare nuovamente un altro nome file.

Ora l'allegato bashdeve essere rilasciato e possiamo uscire gdb:

(gdb) detach
Detaching from program: /bin/bash, process <PID>
(gdb) q

Se lo script è stato interrotto da gdbun altro terminale, continua a essere eseguito. Possiamo tornare al terminale di loop.sh. Ora non scrive nulla sullo schermo, ma esegue e scrive nel file. Dobbiamo metterlo in secondo piano. Quindi premere ^Z.

^Z
[1]+  Stopped                 ./loop.sh

(Ora siamo nello stesso stato come se ^Zfosse stato premuto all'inizio.)

Ora possiamo verificare lo stato del lavoro:

$ ps -f 24522
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh
$ jobs
[1]+  Stopped                 ./loop.sh

Quindi il processo dovrebbe essere in esecuzione in background e staccato dal terminale. Il numero jobsnell'output del comando tra parentesi quadre identifica il lavoro all'interno bash. Possiamo usare i seguenti bashcomandi integrati che applicano un segno '%' prima del numero del lavoro:

$ bg %1
[1]+ ./loop.sh &
$ disown -h %1
$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh

E ora possiamo uscire dalla bash chiamante. Il processo continua in esecuzione in background. Se abbandoniamo il suo PPID diventiamo 1 (processo init (1)) e il terminale di controllo diventa sconosciuto.

$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID>     1  0 11:16 ?        S      0:00 /bin/bash ./loop.sh
$ /usr/bin/lsof -p <PID>
...
loop.sh <PID> truey    0u   CHR 136,36                38 /dev/pts/36 (deleted)
loop.sh <PID> truey    1u   REG   0,26     1127 15008411 /home/truey/loop.out
loop.sh <PID> truey    2u   CHR 136,36                38 /dev/pts/36 (deleted)

COMMENTO

Le cose di gdb possono essere automatizzate creando un file (ad esempio loop.gdb) contenente i comandi ed esegui gdb -q -x loop.gdb -p <PID>. Il mio loop.gdb è simile al seguente:

call close(1)
call open("loop.out", 01102, 0600)
# call close(2)
# call open("loop.err", 01102, 0600)
detach
quit

Oppure si può usare invece il seguente liner:

gdb -q -ex 'call close(1)' -ex 'call open("loop.out", 01102, 0600)' -ex detach -ex quit -p <PID>

Spero che questa sia una descrizione abbastanza completa della soluzione.


Davvero molto istruttivo e probabilmente funzionerà bene in casi semplici. Ma attenzione, i casi più complessi possono fallire miseramente. Ne avevo uno oggi: il mio processo aveva favorito un altro processo che produceva l'output (presumibilmente a stderr), ma che era stato collegato per la comunicazione con il suo master. Il reindirizzamento degli FD dei master non ha avuto effetto perché il bambino ha ereditato stderr e la chiusura dello stdout del bambino ha fallito il master che stava aspettando dall'altra parte della pipa. X | Bettern conosce i tuoi processi molto prima di provare questo.
cmaster - ripristina monica il

@cmaster È possibile verificare se un handle viene reindirizzato utilizzando lsof(il nome dell'handle del file è pipe, non simile /dev/pts/1) o tramite ls -l /proc/<PID>/fd/<fd>(questo mostra il collegamento simbolico dell'handle). Inoltre, i sottoprocessi non possono ancora avere reindirizzati output, che devono essere reindirizzati a un file.
Vero

7

Per inviare il processo in esecuzione a nohup ( http://en.wikipedia.org/wiki/Nohup )

nohup -p pid , non ha funzionato per me

Quindi ho provato i seguenti comandi e ha funzionato molto bene

  1. Esegui qualche SOMECOMMAND, diciamo /usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1.

  2. Ctrl+ Zper interrompere (mettere in pausa) il programma e tornare alla shell.

  3. bg per eseguirlo in background.

  4. disown -h in modo che il processo non venga interrotto alla chiusura del terminale.

  5. Digita exitper uscire dalla shell perché ora sei a posto perché l'operazione verrà eseguita in background nel suo stesso processo, quindi non è legata a una shell.

Questo processo è l'equivalente della corsa nohup SOMECOMMAND.


3

Sul mio sistema AIX, ho provato

nohup -p  processid>

Questo ha funzionato bene. Ha continuato a eseguire il mio processo anche dopo aver chiuso le finestre del terminale. Abbiamo ksh come shell predefinita, quindi i comandi bge disownnon hanno funzionato.


2
  1. ctrl+ z - questo metterà in pausa il lavoro (non annullerà!)
  2. bg - questo metterà il lavoro in background e tornerà in esecuzione
  3. disown -a - questo taglierà tutti gli allegati con il lavoro (quindi puoi chiudere il terminale e continuerà a funzionare)

Questi semplici passaggi ti permetteranno di chiudere il terminale mantenendo il processo in esecuzione.

Non indosserà nohup(in base alla mia comprensione della tua domanda, non ne hai bisogno qui).


Penso che il comportamento da disconoscere -a sia quello di tagliare l'attaccamento con tutti i lavori. Tuttavia, non arresta le pipeline stdin / stdout, il che significa che il processo tenterà comunque di scrivere (/ leggere) dal terminale
Kelthar,

-2

Questo ha funzionato per me su Ubuntu Linux mentre era in tcshell.

  1. CtrlZ per metterlo in pausa

  2. bg per eseguire in background

  3. jobs per ottenere il suo numero di lavoro

  4. nohup %n dove n è il numero del lavoro


2
No, non funziona:nohup: failed to run command '%1': No such file or directory
Dunatotatos,
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.