Linux / Comando nohup: manter tarefas em execução após sair da sessão

nohup é uma ferramenta que executa um comando ignorando o sinal SIGHUP, que pode ser enviado quando a conexão do terminal é perdida. Para continuar uma tarefa após o logout, é comum usar nohup junto com o símbolo de execução em segundo plano &, sendo também recomendado especificar explicitamente os arquivos de entrada e saída padrão.

A forma básica mais prática é a seguinte.

nohup ./worker.sh > worker.log 2>&1 < /dev/null &

No entanto, nohup não é um gerenciador de serviços que monitora ou reinicia processos. Para serviços que precisam iniciar com o sistema, reiniciar após falhas ou ter seus logs administrados, ferramentas de gerenciamento de serviços como systemd são mais adequadas.

O que o comando nohup faz?

nohup executa o comando especificado após configurá-lo para ignorar o sinal de desconexão (hangup), SIGHUP. Ao fechar um terminal ou encerrar uma conexão SSH (Secure Shell, protocolo de acesso remoto seguro), SIGHUP pode ser enviado para o shell e processos relacionados, e ignorá-lo aumenta a probabilidade de que a tarefa continue sendo executada.

Como pode ser visto na explicação oficial do GNU Coreutils sobre nohup, nohup em si não envia um comando para o segundo plano. Para continuar outros trabalhos no terminal atual, você precisa adicionar separadamente & no final do comando.

Componentes O que ele faz O que ele não faz
nohup Faz o comando a ser executado ignorar SIGHUP. Não executa automaticamente em segundo plano.
& Faz o shell executar o comando como um trabalho em segundo plano. Não garante que o SIGHUP seja ignorado.
Redirecionamento de saída Envia a saída padrão e erros para o arquivo de log especificado. Não impõe limites de tamanho de log ou exclusão automática.

Sintaxe básica e forma de execução recomendada

Sintaxe básica

Após nohup, escreva o comando e os argumentos a serem executados em ordem.

nohup command [arg ...]

Os nomes worker.sh, backup.sh e worker representam programas que você já tem; o nohup não os cria nem instala. Verifique o caminho, a permissão de execução e o interpretador indicado na primeira linha dos scripts. Se necessário, conceda execução somente ao seu script com chmod u+x backup.sh.

Para um teste simples sem script próprio, substitua apenas ./backup.sh por sleep 60 nos exemplos abaixo. A tarefa dura cerca de um minuto e não produz saída; portanto, o arquivo backup.log pode ficar vazio. Você poderá observar o PID enquanto ela estiver ativa e encerrá-la pelo procedimento descrito adiante.

Para executar seu arquivo backup.sh no diretório atual, use:

nohup ./backup.sh

Esta forma ignora SIGHUP, mas executa em primeiro plano. Portanto, é difícil inserir o próximo comando no mesmo shell até que o comando termine.

Execução em segundo plano e armazenamento de logs

No trabalho real, é mais fácil gerenciar se você especificar a execução em segundo plano e o caminho do log juntos.

nohup ./backup.sh > backup.log 2>&1 < /dev/null &
  • > backup.log grava a saída padrão em um novo arquivo de log. Se o mesmo arquivo existir, ele sobrescreve o conteúdo existente.
  • 2>&1 envia o erro padrão para o mesmo lugar que a saída padrão atual.
  • < /dev/null faz a entrada padrão vir de /dev/null, que retorna fim de arquivo (EOF) ao ser lido, em vez de aguardar uma digitação no terminal.
  • O último & executa o comando em segundo plano.

Para anexar novo conteúdo a um log existente, use >> em vez de >.

nohup ./backup.sh >> backup.log 2>&1 < /dev/null &

Salve o PID imediatamente após a execução

Logo após executar um comando em segundo plano, $! contém o identificador do processo (PID, de process ID) do trabalho em segundo plano mais recentemente iniciado. É conveniente registrar esse valor em um local seguro para verificar o status posteriormente ou terminar o processo.

nohup ./backup.sh > backup.log 2>&1 < /dev/null &
job_pid=$!
printf '%s\n' "$job_pid" > backup.pid

Coloque o arquivo PID em um diretório ao qual apenas o usuário que gerencia o trabalho tenha permissão de gravação. Se arquivos PID antigos permanecerem, o mesmo número pode ser usado por outro processo posteriormente, por isso, confirme o comando e o horário de início antes de encerrar um processo.

Como a entrada e a saída padrão são tratadas?

Entrada padrão

Na implementação GNU, se a entrada padrão estiver conectada a um terminal, nohup a substitui por uma fonte da qual não é possível ler. Esse comportamento reduz situações em que o programa para esperando por entrada após o terminal desaparecer. Para reduzir diferenças de implementação e esclarecer a intenção, você pode escrever explicitamente < /dev/null no comando.

Saída padrão e nohup.out

Se a saída padrão for direcionada ao terminal e nenhum redirecionamento separado for especificado, o GNU nohup anexa a saída a nohup.out no diretório atual. Se não puder gravar nesse arquivo, ele tenta nohup.out no diretório pessoal do usuário, e se ambos os locais não forem graváveis, o comando não será executado.

Se várias tarefas compartilharem o mesmo nohup.out, pode ser difícil distinguir a qual tarefa os registros pertencem, e o arquivo pode continuar a crescer. É melhor especificar um arquivo de log com um nome e política de retenção para cada tarefa.

Erro padrão

Se o erro padrão for direcionado ao terminal, o GNU nohup geralmente o envia para o mesmo destino que a saída padrão. No entanto, dependendo do shell, sistema operacional ou redirecionamentos aplicados anteriormente, os leitores podem interpretar os resultados de forma equivocada, então é mais seguro indicar explicitamente sua intenção usando 2>&1. A ordem importa: o shell processa os redirecionamentos da esquerda para a direita. Em > backup.log 2>&1, a saída padrão vai para o arquivo antes de o erro padrão ser ligado ao mesmo destino. Consulte o manual de redirecionamentos do Bash para entender essa ordem.

Como verificar o estado da execução e os logs

Como verificar processos pelo PID salvo

Se você tiver o PID salvo logo após a execução, pode passá-lo diretamente para ps para verificar seu status.

job_pid=$(cat backup.pid)
ps -p "$job_pid" -o pid,ppid,stat,etime,cmd

PID é o ID do processo, PPID é o ID do processo pai, STAT é o status, e ELAPSED é o tempo decorrido desde o início, e não o tempo de CPU consumido. Não assuma que é a tarefa desejada apenas porque o PID existe; verifique também a coluna de comando no final.

Encontrando um processo pelo nome

Se o PID não foi salvo, você pode procurar a linha de comando com pgrep.

pgrep -af 'backup.sh'

Como outros processos contendo a mesma string também podem ser encontrados, você deve verificar toda a linha de comando do resultado. Simplesmente direcionar a saída do ps para o grep frequentemente mostra o próprio comando de busca e, portanto, não é adequado para automação.

Verificando logs em tempo real

Usar o tail -f permite que você visualize continuamente adições ao final de um arquivo.

tail -f backup.log

Para parar de monitorar o log, pressione Ctrl+C. Isso apenas termina o tail e não interrompe a tarefa original que está escrevendo o log. Você pode ver mais detalhes sobre como especificar o número de linhas e acompanhar arquivos em como usar o comando tail.

Terminando um processo iniciado com nohup

Primeiro, solicite um encerramento normal

Depois de verificar o PID alvo e o comando, executar kill basicamente envia o sinal SIGTERM. Se o programa tiver código de tratamento de encerramento, ele terá a chance de fechar arquivos e limpar seu estado.

job_pid=$(cat backup.pid)
ps -p "$job_pid" -o pid,ppid,stat,etime,cmd
kill "$job_pid"

Verificando se ele terminou

Espere um momento e então verifique o mesmo PID novamente.

ps -p "$job_pid" -o pid,stat,etime,cmd

Se um script shell criou múltiplos processos filhos, terminar apenas um pai pode deixar os filhos em execução. Verifique primeiro a árvore de processos e os grupos de processos, e se o programa que você está usando fornecer um comando oficial de encerramento, priorize usá-lo.

Use o encerramento forçado como último recurso

Se você forçar o encerramento imediatamente só porque o processo não responde ao SIGTERM, os dados podem não ser salvos, ou arquivos temporários podem não ser limpos. Certifique-se de que a causa e o alvo estão corretos, e use SIGKILL apenas como último recurso.

kill -KILL "$job_pid"

Executando pipelines e comandos compostos

Agrupando em um único comando de shell

Você pode passar uma string de comando para o shell para executar um pipeline, vários redirecionamentos e operadores condicionais como uma única tarefa. No exemplo, producer e consumer são nomes ilustrativos: substitua-os pelos programas reais que geram e consomem os dados.

nohup sh -c 'producer | consumer' > pipeline.log 2>&1 < /dev/null &

Nesse caso, o pipeline dentro das aspas é interpretado por um novo shell. Se você mesclar entradas externas na string de comando sem validação, há um risco de injeção de comandos, portanto, não insira valores não confiáveis diretamente. Consulte também o uso dos operadores de comandos do Bash (em inglês) para entender como esses operadores relacionam a execução dos comandos.

Quando os logs não estão imediatamente visíveis

Se o processo está em execução, mas os logs aparecem tardiamente, a causa pode ser o buffer de saída do programa em vez de nohup. Primeiro, verifique as configurações de descarregamento do buffer (flush) do próprio programa; isso significa enviar os dados pendentes ao destino, sem apagar o log. Em ambientes baseados em GNU, se o programa e o método de saída forem compatíveis, você pode solicitar armazenamento em buffer por linha com stdbuf.

nohup stdbuf -oL -eL ./worker > worker.log 2>&1 < /dev/null &

stdbuf não funciona para todos os programas. Segundo o manual do GNU Coreutils sobre stdbuf, o programa precisa usar os fluxos FILE da biblioteca C e não redefinir o próprio armazenamento em buffer.

Limites do nohup e critérios para escolher outras ferramentas

Recursos não fornecidos pelo nohup

nohup é uma ferramenta de execução simples que altera o tratamento de um sinal. Os seguintes recursos não são fornecidos.

  • Início automático após reinício do sistema
  • Reinício automático quando o processo termina de forma anormal
  • Gerenciamento da ordem de inicialização de serviços dependentes
  • Limitação de recursos e monitoramento de status, como CPU e memória
  • Limitação de tamanho de arquivo de log, compressão, retenção e exclusão
  • Preservação de sessões interativas de terminal

Diferenças em relação a systemd, tmux e screen

Ferramentas Situações adequadas Recursos
nohup Execução temporária de tarefas em lote não interativas Simples, mas não possui funções de monitoramento, reinício ou rotação de logs.
systemd Serviços que rodam continuamente no servidor Você pode configurar integração na inicialização, políticas de reinício, dependências e gerenciar logs e recursos.
tmux (em inglês)/screen Tarefas interativas que precisam ser reconectadas mais tarde Você pode desconectar e reconectar sessões de terminal virtual.
Agendador de tarefas Tarefas a serem executadas em um horário ou intervalo fixo Agende as execuções com cron ou uma fila de tarefas dedicada; a retenção do histórico depende da ferramenta e da configuração.

Diferença em relação a disown

disown é um recurso interno de shell em alguns shells como o Bash que remove um trabalho já iniciado da lista de trabalhos do shell ou altera o método de tratamento do sinal de desconexão. Em contraste, nohup é um programa externo que faz com que um comando ignore SIGHUP desde o momento em que é iniciado. No Bash, disown -h mantém o trabalho na lista, mas impede que o shell lhe repasse SIGHUP quando o próprio shell recebe esse sinal. Esse comportamento é descrito no manual de sinais do Bash. As opções variam entre shells; consulte a documentação do shell usado no seu script.

Checklist para execução segura

  • Caminho: Especifique scripts, arquivos de configuração e arquivos de log pelo caminho absoluto sempre que possível. Isso garante que os mesmos arquivos sejam usados mesmo que o local de login mude.
  • Permissões: Verifique se senhas, tokens ou informações pessoais podem permanecer nos registros e restrinja as permissões de arquivos.
  • Tamanho: Configure logrotate ou a própria política de retenção de logs do programa para evitar que os registros cresçam continuamente.
  • Execução duplicada: Verifique se é seguro que a mesma tarefa seja executada várias vezes simultaneamente. Se necessário, use arquivos de bloqueio ou o recurso de execução única do programa.
  • Ambiente: Em execução não interativa, confirme o diretório de trabalho, PATH, a configuração regional (locale) e as variáveis necessárias. O nohup herda o ambiente de quem o inicia; diferenças aparecem se a tarefa for iniciada por outro shell, conta ou agendador.
  • Argumentos sensíveis: Se você passar senhas ou tokens como argumentos de linha de comando, outros usuários poderão vê-los na lista de processos. Use arquivos de credenciais ou métodos de armazenamento seguro suportados pelo programa.
  • Procedimento de encerramento: Registre o PID imediatamente após a execução e prepare tanto o método normal de encerramento quanto os passos para verificar quaisquer processos filhos restantes.

Perguntas frequentes

Um trabalho com nohup definitivamente continuará se eu fechar a janela SSH?

Comandos iniciados com nohup ignoram SIGHUP, mas isso não garante absolutamente a persistência do trabalho em todos os ambientes. Se um programa criar processos filhos separados enquanto altera as configurações de sinal ou continuar usando o dispositivo do terminal, o resultado pode variar. Desvincule a entrada padrão, a saída padrão e o erro padrão do terminal. Há ainda políticas de sessão: por exemplo, se KillUserProcesses=yes estiver em vigor, o systemd-logind pode encerrar os processos no escopo da sessão ao sair, conforme o manual de logind.conf. Para tarefas importantes de longa execução, use um gerenciador de serviços com a configuração apropriada.

Como posso evitar a criação do arquivo nohup.out?

Você pode especificar diretamente a saída padrão e o erro padrão. Apenas tarefas que não requerem nenhum registro podem ser enviadas para /dev/null, mas, como informações de diagnóstico também serão perdidas, geralmente é recomendado usar arquivos de log separados para tarefas operacionais.

nohup ./worker > /dev/null 2>&1 < /dev/null &

Por que os trabalhos não aparecem em jobs?

jobs mostra apenas tarefas gerenciadas pelo shell atual. Se você fizer logout e se conectar com um novo shell, a lista de trabalhos do shell anterior não é transferida, então não aparecerá em jobs. Use o PID salvo e ps, ou use a função de verificação de status das ferramentas de gerenciamento de serviço.

O que significa o código de saída do nohup?

Na implementação GNU, códigos de saída separados são usados para erros no próprio nohup, casos em que o comando não pode ser encontrado ou casos em que o comando não pode ser executado. Se o comando iniciar com sucesso, ele retorna o status de saída desse comando. O valor exato pode ser afetado pela implementação e pela configuração POSIXLY_CORRECT, portanto, para automação, verifique nohup --help e a documentação oficial do sistema. O $? lido logo após iniciar a tarefa com & não é o resultado final do processo em segundo plano. Enquanto o mesmo shell ainda gerenciar esse filho, wait "$job_pid" permite aguardar e consultar seu resultado. Depois de sair e abrir outro shell, você não recupera esse resultado apenas lendo $?; use os logs ou o registro de estado do programa.

Resumo

nohup executa um comando de modo que ele ignore SIGHUP, o que pode ocorrer ao fazer logout ou fechar o terminal. Tarefas não interativas típicas usam nohup juntamente com & e redirecionamento explícito de entrada/saída padrão, e salvar o PID imediatamente após a execução torna o gerenciamento mais fácil.

Se a tarefa precisa iniciar mesmo após um reinício ou requer recuperação automática em caso de falha, escolha um gerenciador de serviços como systemd em vez de nohup. Para dar uma olhada em outras ferramentas básicas rapidamente, você pode consultar a lista de comandos frequentes do Linux (em inglês).