Come posso mettere un processo già in esecuzione sotto nohup?
Domanda
Ho un processo che è già in esecuzione da molto tempo e non voglio interromperlo.
Come lo inserisco in nohup (ovvero, come faccio a farlo continuare anche se chiudo il terminale?)
Soluzione
Utilizzo del Controllo lavoro di bash per inviare il processo nel sfondo:
- Ctrl + Z per interrompere (mettere in pausa) il programma e tornare alla shell.
-
bg
per eseguirlo in background. -
disown -h [job-spec]
dove [specifica lavoro] è il numero del lavoro (come%1
per il primo lavoro in esecuzione; trova il tuo numero con il comandojobs
) in modo che il lavoro non venga interrotto alla chiusura del terminale .
Altri suggerimenti
Supponiamo che per qualche motivo Ctrl + Z non funzioni, vai su un altro terminale, trova l'id del processo (usando ps
) ed esegui:
kill -SIGSTOP PID
kill -SIGCONT PID
SIGSTOP
sospenderà il processo e SIGCONT
riprenderà il processo, in background. Quindi ora chiudere entrambi i terminali non interromperà il processo.
Il comando per separare un processo in esecuzione dalla shell (= lo rende nohup) è disown
e un 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 lo è rimosso dalla tabella, ma è contrassegnato in modo che SIGHUP non venga inviato al lavoro se la shell riceve un SIGHUP. Se non c'è jobspec presente 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 ritorno il valore è 0 a meno che un jobspec non specifichi un lavoro valido.
Ciò significa che è un semplice
disown -a
rimuoverà tutti i lavori dalla tabella dei lavori e li renderà nohup
Queste sono buone risposte sopra, volevo solo aggiungere un chiarimento:
Non puoi disown
un pid o processo, tu <=> un 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.
Edizione:
% jobs
[1] running java
[2] suspended vi
% disown %1
Vedi http://www.quantprinciple.com/ investire / index.php / docs / TipsAndTricks / unix / JobControl / per una discussione più dettagliata di Unix Job Control.
Purtroppo disown
è specifico per bash e non disponibile in tutte le shell.
Alcune versioni di Unix (ad esempio AIX e Solaris) hanno un'opzione sul comando nohup
stesso che può essere applicato a un processo in esecuzione:
nohup -p pid
La risposta del nodo è davvero eccezionale, ma ha lasciato aperta la domanda su come ottenere reindirizzamento di stdout e stderr. Ho trovato una soluzione su Unix & Amp; Linux , ma non è completo. Vorrei unire queste due soluzioni. Eccolo:
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 gdb
dovrebbe essere allegato 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 campo STAT
è '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_WRONLY
potrebbe essere applicato, ma /usr/sbin/lsof
dice 'u' per tutti i gestori di file std * (FD
colonna), che è O_APPEND
.
Ho controllato i valori nel file di intestazione /usr/include/bits/fcntl.h.
Il file di output potrebbe essere aperto con nohup
, come farebbe man open(2)
, ma ciò non è suggerito da call perror("")
, a causa di possibili problemi di NFS.
Se otteniamo -1 come valore di ritorno, p errno
stampa il messaggio di errore. Se abbiamo bisogno dell'errno, usa /usr/sbin/lsof -p <PID>
comando gdb.
Ora possiamo controllare il file appena reindirizzato. call close(2)
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 nuovamente call open(...)
e bash
usando un altro nome file.
Ora il ^Z
allegato deve essere rilasciato e possiamo uscire da jobs
:
(gdb) detach
Detaching from program: /bin/bash, process <PID>
(gdb) q
Se lo script è stato interrotto da gdb -q -x loop.gdb -p <PID>
da un 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
[1]+ Stopped ./loop.sh
(Ora siamo nello stesso stato come se <=> fosse premuto all'inizio.)
Ora possiamo controllare 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 nell'output del comando <=> tra parentesi quadre identifica il lavoro all'interno di <=>. Possiamo usare i seguenti comandi <=> 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 eseguendo <=>. 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.
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
-
Esegui SOMECOMMAND, dì
/usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1
. Ctrl + Z per interrompere (mettere in pausa) il programma e tornare alla shell.
-
bg
per eseguirlo in background. -
disown -h
in modo che il processo non venga interrotto alla chiusura del terminale. -
Digita
exit
per 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 equivale all'esecuzione di nohup SOMECOMMAND
.
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 di default, quindi i comandi bg
e disown
non hanno funzionato.
- ctrl + z - questo interromperà il lavoro (non verrà annullato!)
-
bg
- questo metterà il lavoro in background e ritornerà nel processo in esecuzione -
disown -a
- questo taglierà tutti gli allegati con il lavoro (in modo da poter chiudere il terminale e continuerà a funzionare)
Questi semplici passaggi ti permetteranno di chiudere il terminale mantenendo il processo in esecuzione.
Non inserirà nohup
(in base alla mia comprensione della tua domanda, non ne hai bisogno qui).
Questo ha funzionato per me su Ubuntu Linux mentre era in tcshell.
Ctrl Z per metterlo in pausa
-
bg
per l'esecuzione in background -
jobs
per ottenere il numero di lavoro -
nohup %n
dove n è il numero del lavoro