Bem-vindo à aula sobre controle de jobs no shell Bash. Quando você executa um comando no terminal, ele normalmente roda em primeiro plano (foreground), bloqueando o terminal até que termine. Porém, em muitas situações – como iniciar um servidor, uma compilação longa ou um script de backup – é útil executar tarefas em segundo plano (background) e continuar trabalhando no terminal. O Bash oferece um conjunto de ferramentas para gerenciar esses processos, chamados de jobs.

Dominar o controle de jobs é essencial para qualquer usuário avançado de Linux, pois permite maior produtividade e flexibilidade no gerenciamento de tarefas. Nesta aula, exploraremos os conceitos de foreground e background, os comandos jobs, fg, bg, o atalho de teclado Ctrl+Z, e as ferramentas nohup e disown para manter processos rodando mesmo após o logout.

Foreground e background (&)

No terminal, todo comando executado normalmente roda em primeiro plano. Isso significa que o shell espera o comando terminar antes de exibir o prompt novamente. Durante esse período, você não pode digitar outros comandos (a menos que o comando aceite entrada, mas o terminal fica bloqueado). Por exemplo, se você executar sleep 10, o prompt só retorna após 10 segundos.

Para executar um comando em segundo plano, basta adicionar o caractere & ao final do comando. O shell então inicia o processo em background e retorna imediatamente o prompt, permitindo que você continue trabalhando. O processo em background continua rodando independentemente, mas sua saída padrão (stdout) ainda vai para o terminal (a menos que você redirecione).

Exemplo:

sleep 30 &

Ao executar, o shell exibe algo como [1] 12345, onde [1] é o número do job e 12345 é o PID (identificador do processo). Você pode continuar digitando comandos normalmente.

É importante redirecionar a saída de comandos em background para um arquivo, para evitar que mensagens interrompam seu trabalho. Por exemplo:

./meu_script.sh > saida.log 2>&1 &

Isso envia tanto a saída padrão quanto os erros para o arquivo saida.log.

jobs, fg, bg

O Bash permite gerenciar múltiplos jobs com os comandos jobs, fg e bg. Vamos entender cada um.

jobs: lista os jobs ativos (em background ou suspensos) associados ao shell atual. A saída mostra o número do job, seu estado (Running, Stopped, etc.) e o comando executado. Exemplo:

$ sleep 100 &
[1] 12345
$ jobs
[1]+  Running                 sleep 100 &

fg: traz um job em background ou suspenso para o primeiro plano. A sintaxe é fg %n, onde n é o número do job (ou % para o job atual). Sem argumento, fg opera sobre o job marcado com + (o mais recente).

fg %1

Isso coloca o job 1 em primeiro plano, e o shell espera ele terminar.

bg: retoma um job suspenso (Stopped) em segundo plano. Se um job foi interrompido com Ctrl+Z, você pode usar bg %n para fazê-lo continuar rodando em background. Sem argumento, usa o job atual.

$ sleep 100
^Z
[1]+  Stopped                 sleep 100
$ bg %1
[1]+ sleep 100 &

Esses comandos são fundamentais para alternar entre tarefas sem perder o controle.

Ctrl+Z

A combinação de teclas Ctrl+Z suspende (pausa) o processo em primeiro plano, enviando o sinal SIGTSTP. O processo não é encerrado, apenas interrompido, e o shell mostra uma mensagem como [1]+ Stopped. O processo fica em estado Stopped e pode ser retomado com fg (em primeiro plano) ou bg (em segundo plano).

Exemplo prático:

$ sleep 60
^Z
[1]+  Stopped                 sleep 60
$ jobs
[1]+  Stopped                 sleep 60
$ bg
[1]+ sleep 60 &

Ctrl+Z é útil quando você quer pausar um processo para fazer outra coisa no terminal e depois retomá-lo. Diferente de Ctrl+C, que envia SIGINT e encerra o processo, Ctrl+Z apenas suspende.

É importante notar que, se você sair do shell (logout) com jobs suspensos ou em background, eles podem ser encerrados (dependendo das configurações). Para evitar isso, use nohup ou disown.

nohup e disown

Quando você executa um processo em background e fecha o terminal, o processo normalmente recebe o sinal SIGHUP e é encerrado. Para evitar isso, existem duas ferramentas: nohup e disown.

nohup (no hangup) é um comando que executa outro comando ignorando o sinal SIGHUP. A sintaxe é nohup comando [argumentos] &. Ele redireciona automaticamente a saída para o arquivo nohup.out se você não redirecionar. Exemplo:

nohup ./meu_servidor.sh > /dev/null 2>&1 &

Isso inicia o script e o mantém rodando mesmo após o logout, sem gerar arquivo de log.

disown é um builtin do Bash que remove um job da tabela de jobs do shell, fazendo com que o shell não envie SIGHUP quando você sair. Você pode usar disown %n para remover um job específico, ou disown -a para remover todos. Exemplo:

sleep 100 &
[1] 12345
disown %1

Agora o processo sleep continua rodando mesmo se você fechar o terminal. Diferente de nohup, disown não redireciona a saída, então é bom redirecionar manualmente.

Ambos são úteis para tarefas de longa duração, como servidores web, downloads grandes ou processamento de dados.

Referências

Exercícios

  1. Explique a diferença entre executar um comando com & no final e usar Ctrl+Z em um processo em primeiro plano.
  2. ✓ Resposta: Executar com & inicia o processo já em segundo plano, retornando o prompt imediatamente. Ctrl+Z suspende um processo que está em primeiro plano, pausando-o; ele pode ser retomado com fg ou bg. Ambos permitem continuar usando o terminal, mas & não pausa o processo, apenas o coloca em background desde o início.
  3. Você iniciou um job em background com o comando find / -name "*.txt" > arquivos.txt &. Como você pode verificar se ele ainda está rodando e, se necessário, trazê-lo para o primeiro plano?
  4. ✓ Resposta: Use jobs para listar os jobs ativos. Se o job estiver listado com estado Running, ele ainda está em execução. Para trazê-lo para o primeiro plano, use fg %n, onde n é o número do job. Por exemplo, se o job for o número 1, digite fg %1.
  5. Escreva um comando que execute um script chamado backup.sh em segundo plano, redirecionando toda a saída (stdout e stderr) para um arquivo backup.log, e que o processo sobreviva ao logout sem usar nohup.
  6. ✓ Resposta: Você pode iniciar o script em background e depois usar disown para removê-lo da tabela de jobs, evitando que o shell envie SIGHUP. Exemplo:
    ./backup.sh > backup.log 2>&1 &
    disown %1
    
  7. Qual é a diferença entre nohup e disown? Cite uma situação em que cada um é mais apropriado.
  8. ✓ Resposta: nohup é um comando que ignora o sinal SIGHUP para o processo que ele executa, e redireciona a saída para nohup.out se não for redirecionada. disown é um builtin do shell que remove o job da lista de jobs, impedindo que o shell envie SIGHUP ao sair. Use nohup quando você quiser uma solução simples para iniciar um processo que deve continuar após o logout, e disown quando o processo já está rodando e você quer desvinculá-lo do shell sem interrompê-lo.
  9. Se você tem um processo suspenso (Stopped) e deseja retomá-lo em segundo plano, qual comando você usaria? Dê um exemplo.
  10. ✓ Resposta: Use o comando bg. Por exemplo, se o job 2 está suspenso, digite bg %2 para retomá-lo em segundo plano. Se não especificar o número, o job atual (marcado com +) será usado.

Boas práticas e observações finais

Ao trabalhar com jobs, é importante ter cuidado com a saída dos processos em background, pois eles podem poluir o terminal. Sempre redirecione a saída para arquivos ou para /dev/null quando não precisar dela. Além disso, lembre-se de que processos em background são filhos do shell; se o shell for encerrado, eles podem ser encerrados, a menos que você use nohup ou disown.

Outra dica: use kill %n para encerrar um job específico. Isso é útil quando você não sabe o PID, mas conhece o número do job. Por exemplo, kill %1 envia SIGTERM para o job 1.