Linux / Comando nohup: eseguire lavori dopo il logout
nohup è uno strumento che esegue un comando ignorando il segnale SIGHUP, che può essere inviato quando la connessione al terminale viene persa. Per continuare un'attività dopo il logout, è comune usare nohup insieme al simbolo di esecuzione in background &, ed è anche consigliato specificare esplicitamente i file di input e output standard.
Per una prova riproducibile, usa una nuova directory di lavoro e verifica che non contenga già worker.sh o worker.log: questo esempio li crea o li sovrascrive. Lo script stampa started, attende cinque secondi e stampa done. L’invocazione di nohup lo avvia in background; l’ultima riga mostra il PID, cioè il numero identificativo del processo.
cat > worker.sh <<'EOF'
#!/bin/sh
printf '%s\n' started
sleep 5
printf '%s\n' done
EOF
chmod u+x worker.sh
nohup ./worker.sh > worker.log 2>&1 < /dev/null &
job_pid=$!
printf 'PID=%s\n' "$job_pid"
Dopo circa cinque secondi, cat worker.log mostra le righe started e done, salvo ritardi o errori del sistema. Prima di chiudere questa shell puoi usare wait "$job_pid" e controllare $?: per lo script dimostrativo il risultato atteso è 0. Gli altri esempi sotto illustrano operazioni alternative, non una sequenza da eseguire tutta sullo stesso lavoro.
Tuttavia, nohup non è un gestore di servizi che monitora o riavvia i processi. Per servizi a lungo termine che richiedono l'avvio automatico dopo il riavvio, il riavvio in caso di errore o la rotazione dei log, strumenti di gestione dei servizi come systemd sono più adatti.
Cosa fa il comando nohup?
nohup esegue il comando specificato dopo averlo impostato per ignorare il segnale di hangup, SIGHUP. Quando si chiude un terminale o si termina una connessione SSH, SIGHUP può essere inviato alla shell e ai processi correlati, e ignorarlo aumenta la probabilità che il compito continui a essere eseguito.
Come si può vedere nella documentazione GNU di nohup, nohup di per sé non invia un comando in background. Per continuare altri lavori nel terminale corrente, è necessario aggiungere separatamente & alla fine del comando.
| Componenti | Cosa fa | Cosa non fa |
|---|---|---|
nohup |
Fa sì che il comando da eseguire ignori SIGHUP. |
Non avvia automaticamente il comando in background. |
& |
Fa sì che la shell esegua il comando come lavoro in background. | Non garantisce di ignorare SIGHUP. |
| Redirezione dell’uscita | Invia l'output standard e gli errori al file di log specificato. | Non impone limiti di dimensione del log né cancellazioni automatiche. |
Sintassi e avvio consigliato
Sintassi di base
Dopo nohup, indica l’eseguibile e i suoi argomenti. command e arg sono segnaposto; le parentesi quadre dello schema non vanno copiate.
nohup command [arg ...]
Gli esempi seguenti con backup.sh presuppongono uno script di backup già esistente, eseguibile e verificato. Non lanciarli su dati reali solo per provare nohup: per l’esercizio usa lo script worker.sh iniziale e adatta i nomi dei file.
nohup ./backup.sh
Questa forma ignora SIGHUP ma rimane in primo piano: la shell attende che il comando termini. Nohup non crea automaticamente un processo demone né una nuova sessione di login.
Esecuzione in background e salvataggio del log
Per un’attività non interattiva, specifica insieme esecuzione in background e destinazioni dei tre flussi standard.
nohup ./backup.sh > backup.log 2>&1 < /dev/null &
> backup.logscrive l'output standard in un nuovo file di log. Se lo stesso file esiste, sovrascrive il contenuto esistente.2>&1invia l'errore standard allo stesso posto dell'output standard corrente.< /dev/nullcollega l’ingresso standard a un file che restituisce subito la fine dell’input (EOF). Non chiude il descrittore: una lettura vede EOF invece di attendere dati dal terminale.- L'ultimo
&esegue il comando in background.
Per aggiungere nuovo contenuto a un log esistente, usa >> invece di >.
nohup ./backup.sh >> backup.log 2>&1 < /dev/null &
Salva il PID immediatamente dopo l'esecuzione
Subito dopo l'esecuzione di un comando in background, $! contiene l'ID del processo (PID) dell'ultimo lavoro in background avviato. È comodo registrare questo valore in un luogo sicuro per controllarne successivamente lo stato o terminare il processo.
nohup ./backup.sh > backup.log 2>&1 < /dev/null &
job_pid=$!
printf '%s\n' "$job_pid" > backup.pid
Posiziona il file PID in una directory in cui solo l'utente che gestisce il lavoro può scrivere. Se rimangono vecchi file PID, lo stesso numero potrebbe essere utilizzato da un altro processo in seguito, quindi verifica identità, comando e ora di avvio prima di inviare un segnale. Il solo numero non garantisce di colpire il processo corretto. Se lo script avvia un processo separato e poi termina, il PID salvato può riferirsi soltanto al processo iniziale: controlla anche i figli.
Come vengono gestiti l'input e l'output standard?
Ingresso standard
Se l’ingresso è un terminale, GNU nohup lo sostituisce con un descrittore non leggibile: un programma che tenta di leggerlo può ricevere un errore. È diverso dal collegamento esplicito a /dev/null, che restituisce EOF. La forma con < /dev/null rende chiaro che non è previsto alcun input interattivo.
Output standard e nohup.out
Se l'output standard è diretto al terminale e non viene specificata una redirezione separata, GNU nohup aggiunge l'output a nohup.out nella directory corrente. Se non è possibile creare un file nella directory corrente, tenta nohup.out nella directory home dell'utente, e se entrambe le posizioni non sono scrivibili, il comando non verrà eseguito.
Se più attività condividono lo stesso nohup.out, può essere difficile distinguere a quale attività appartengono i log e il file può continuare a crescere. È meglio specificare un file di log con un nome e una politica di conservazione per ciascuna attività.
Errore standard
Quando l’errore standard è un terminale, GNU nohup lo collega normalmente all’uscita standard; se quest’ultima è chiusa, può aprire nohup.out per gli errori. Una redirezione esplicita come > backup.log 2>&1 evita ambiguità. Le redirezioni della shell vengono preparate da sinistra a destra: con 2>&1 > backup.log, l’errore resta inizialmente collegato alla precedente destinazione dell’uscita. Nohup può poi applicare le proprie regole se quel flusso è ancora un terminale: specificare prima il file e poi 2>&1 rende il collegamento esplicito. Consulta le regole nella documentazione sulle redirezioni della shell Bash.
Verifica dello stato di esecuzione e dei registri
Controllo dei processi con PID salvato
Se hai salvato il PID nel file backup.pid dell’esempio precedente, puoi consultarlo con procps ps su Linux. Usa lo stesso utente e ambiente di processi in cui il lavoro è stato avviato.
job_pid=$(cat backup.pid)
ps -p "$job_pid" -o pid,ppid,stat,etime,cmd
PID è l'ID del processo, PPID è l'ID del processo padre, STAT è lo stato e il campo etime, normalmente intestato ELAPSED, indica il tempo trascorso dall’avvio. Queste opzioni di ps si riferiscono a procps e possono differire su altri sistemi. Non assumere che sia il compito desiderato solo perché il PID esiste; controlla anche la colonna dei comandi alla fine.
Trovare un processo per nome
Con procps pgrep -af, -f cerca nell’intera riga di comando e -a la visualizza. L’argomento è un’espressione regolare: nell’esempio il punto non è un punto letterale, quindi la ricerca può essere più ampia del nome desiderato.
pgrep -af 'backup.sh'
Poiché possono essere trovati anche altri processi contenenti la stessa stringa, dovresti controllare l'intera riga di comando del risultato. Semplicemente passare l'output di ps a grep spesso mostra il comando di ricerca stesso e pertanto non è adatto per l'automazione.
Controllare i log in tempo reale
Usare tail -f ti permette di visualizzare continuamente le aggiunte alla fine di un file.
tail -f backup.log
Per interrompere il monitoraggio del log, premi Ctrl+C. Se tail è stato avviato separatamente in primo piano, questo interrompe la visualizzazione e non il processo in background che scrive il log. Puoi vedere più dettagli su come specificare il numero di righe e tracciare i file in come usare il comando tail.
Terminare un processo avviato con nohup
Per prima cosa, richiedere una terminazione normale
Dopo aver controllato il PID e il comando di destinazione, kill invia per impostazione predefinita il segnale SIGTERM. Se il programma ha un codice per la gestione della terminazione, ha l'opportunità di chiudere i file e pulire il suo stato.
job_pid=$(cat backup.pid)
ps -p "$job_pid" -o pid,ppid,stat,etime,cmd
kill "$job_pid"
Controllare se è terminato
Attendere un momento e poi controllare di nuovo lo stesso PID.
ps -p "$job_pid" -o pid,stat,etime,cmd
Uno script può creare processi figli che sopravvivono alla sua terminazione. Prima di intervenire, identifica l’albero e i gruppi di processi; preferisci il comando di arresto previsto dall’applicazione. Un processo zombie può ancora comparire in ps pur essendo già terminato: lo stato va interpretato, non solo cercato il PID.
Usare la terminazione forzata come ultima risorsa
Se si forza l'interruzione immediata solo perché non risponde a SIGTERM, i dati potrebbero non essere salvati o i file temporanei potrebbero non essere ripuliti. Assicurati che la causa e l'obiettivo siano corretti e usa SIGKILL solo come ultima risorsa.
kill -KILL "$job_pid"
Esecuzione di pipeline e comandi composti
Raggruppamento in un singolo comando shell
Per una pipeline o un comando composto, passa una stringa a una shell. producer e consumer sono segnaposto da sostituire con programmi reali; per una prova semplice puoi usare printf data | cat.
nohup sh -c 'producer | consumer' > pipeline.log 2>&1 < /dev/null &
La nuova shell interpreta la pipeline tra virgolette. Con nohup producer | consumer, invece, solo producer riceve direttamente il trattamento di nohup. Non concatenare valori non attendibili alla stringa da eseguire. Per l’ordine di esecuzione, consulta la guida agli operatori di concatenazione di Bash.
Quando i log non sono immediatamente visibili
Se il processo è in esecuzione ma i log appaiono in ritardo, la causa potrebbe essere il buffering dell'output del programma piuttosto che nohup. Prima, verifica le impostazioni di flush dei log del programma stesso. In ambienti basati su GNU, se il programma e il metodo di output sono compatibili, puoi richiedere il buffering per linea con stdbuf.
nohup stdbuf -oL -eL ./worker > worker.log 2>&1 < /dev/null &
-oL e -eL richiedono il buffering per riga rispettivamente per uscita ed errore. GNU stdbuf richiede programmi che usino i flussi FILE della libreria C e non ne reimpostino autonomamente il buffering. Non corregge buffer interni arbitrari e non è disponibile su tutte le piattaforme; ./worker qui è un programma dimostrativo da sostituire, distinto da worker.sh.
Limiti di nohup e criteri per la scelta di altri strumenti
Funzionalità non fornite da nohup
nohup è uno strumento di esecuzione semplice che modifica la gestione di un segnale. Le seguenti funzionalità non sono fornite.
- Avvio automatico dopo il riavvio del sistema
- Riavvio automatico quando il processo termina in modo anomalo
- Gestione dell'ordine di avvio dei servizi dipendenti
- Limitazione delle risorse e monitoraggio dello stato come CPU e memoria
- Limitazione delle dimensioni dei file di log, compressione, conservazione e cancellazione
- Conservazione delle sessioni interattive del terminale
Differenze con systemd, tmux, screen
| Strumenti | Situazioni adatte | Caratteristiche |
|---|---|---|
nohup |
Attività batch non interattive eseguite una tantum | Semplice, ma non dispone di funzioni di monitoraggio, riavvio o rotazione dei log. |
systemd |
Servizi che funzionano continuamente sul server | È possibile configurare l'integrazione all'avvio, le politiche di riavvio, le dipendenze e gestire log e risorse. |
tmux/screen |
Attività interattive che devono essere ricollegate più tardi | Puoi separare una sessione di terminale e riconnetterti in seguito; restano applicabili le politiche di chiusura delle sessioni del sistema. |
| Pianificatore di attività | Attività da eseguire a un orario o intervallo fisso | Gestisci la tempistica di esecuzione e la cronologia usando cron o una coda di lavori dedicata. |
Differenza rispetto a disown
In Bash, disown rimuove un lavoro dalla tabella della shell; con disown -h lo lascia nella tabella ma impedisce che la shell gli inoltri SIGHUP. Non modifica allo stesso modo la gestione di ogni segnale ricevuto direttamente dal processo e non reindirizza i flussi già aperti. Nohup imposta invece SIGHUP come ignorato prima di avviare il comando. Le altre shell possono avere regole diverse: consulta il manuale di Bash per disown quando usi questa shell.
Controlli prima dell’avvio
- Percorso: Specifica script, file di configurazione e file di log con percorso assoluto ogni volta che è possibile. Questo garantisce che vengano utilizzati gli stessi file anche se cambia la posizione di accesso.
- Permessi: Verifica se password, token o informazioni personali potrebbero rimanere nei log e limita i permessi dei file.
- Dimensione: Configura
logrotateo la politica di conservazione dei log del programma per evitare che i log crescano continuamente. - Esecuzione duplicata: Verifica se è sicuro che lo stesso compito venga eseguito più volte contemporaneamente. Se necessario, utilizza file di blocco o la funzione di esecuzione singola del programma.
- Ambiente: Nohup eredita directory e ambiente del chiamante; non prepara una nuova shell di login. Una shell non interattiva o un avvio da un altro contesto può usare file di inizializzazione differenti: specifica directory e valori necessari senza includere segreti nei log.
- Argomenti sensibili: Se passi password o token come argomenti della riga di comando, altri utenti possono vederli nella lista dei processi. Usa file di credenziali o metodi di archiviazione sicura supportati dal programma.
- Procedura di terminazione: Registra immediatamente il PID dopo l'esecuzione e prepara sia il metodo di terminazione normale sia i passaggi per controllare eventuali processi figli rimasti.
Domande frequenti
Un lavoro nohup persisterà sicuramente se chiudo la finestra SSH?
No. Nohup protegge da SIGHUP, non da SIGTERM, SIGKILL, riavvii o politiche che terminano i processi della sessione. Per esempio, KillUserProcesses di systemd-logind, se attivo e applicabile all’utente, può terminare lo scope della sessione al logout. Anche il programma può cambiare le proprie impostazioni dei segnali o continuare a usare il terminale. Separa tutti e tre i flussi standard e usa una gestione dei servizi adatta per attività importanti; non modificare le politiche del sistema solo per mantenere un processo.
Come posso evitare la creazione del file nohup.out?
Puoi specificare direttamente l'output standard e l'errore standard. Solo i compiti che non richiedono alcun logging possono essere inviati a /dev/null, ma poiché anche le informazioni diagnostiche andranno perse, di solito si consiglia di utilizzare file di log separati per i compiti operativi.
nohup ./worker > /dev/null 2>&1 < /dev/null &
Perché i lavori non compaiono in jobs?
jobs mostra solo i compiti gestiti dalla shell corrente. Se effettui il logout e ti connetti con una nuova shell, l'elenco dei lavori della shell precedente non viene trasferito, quindi non comparirà in jobs. Usa il PID salvato e ps, oppure utilizza la funzione di controllo dello stato degli strumenti di gestione dei servizi.
Cosa significa il codice di uscita di nohup?
GNU nohup restituisce normalmente 125 per un proprio errore, 126 se trova il comando ma non può avviarlo e 127 se non lo trova; altrimenti restituisce lo stato del comando. Con POSIXLY_CORRECT impostata, gli errori interni valgono 127 anziché 125. Subito dopo una lista asincrona terminata da &, $? non è il risultato finale del lavoro. Nella stessa shell che lo ha avviato puoi usare wait "$job_pid" e leggere subito $?; una nuova shell non può aspettare quel processo come un proprio figlio. Se devi disconnetterti, il programma deve registrare risultato e completamento, oppure deve farlo un gestore di attività.
Riepilogo
nohup esegue un comando in modo da ignorare SIGHUP, che può verificarsi durante il logout o la chiusura del terminale. Per un’attività non interattiva, combina nohup e &, specifica le destinazioni di ingresso, uscita ed errore e salva subito il PID: potrai controllare il lavoro e seguire una procedura di arresto consapevole.
Se l'attività deve avviarsi anche dopo un riavvio o richiede il recupero automatico in caso di errore, scegli un gestore di servizi come systemd invece di nohup. Per dare un'occhiata ad altri strumenti di base a colpo d'occhio, puoi fare riferimento a Elenco dei comandi più usati in Linux.




