Controle de jobs do Bash

controle_jobs-1_abertura

O sistema de controle de jobs do Bash — ou de outra shell padrão POSIX — consiste de um recurso que permite de forma seletiva tanto suspender como restaurar a execução de processos em um sistema. Ele é implementado em conjunto pelo kernel do sistema operacional (mecanismos de controle) e o Bash (interface com o usuário) e antes do surgimento/popularização do console virtual¹, screen, Xterm etc, era a forma de se executar facilmente mais de um programa em um terminal UNIX.

E, claro, ainda continua sendo um recurso muito útil, principalmente quando o único acesso que se tem ao host é via SSH e sem privilégios para instalar o byobu… 🙂

(¹) Por exemplo, me recordo que o BSD/OS possuía somente um console em modo texto.

Interrompendo um processo

Começando com um exemplo bem simples e só para ajudar com os demais. Abra um terminal e digite:

$ ping giovannireisnunes.wordpress.com -i 2

Conte até dez, pressione «Ctrl»+«C» e o resultado na tela será algo mais ou menos assim:

$ ping giovannireisnunes.wordpress.com -i 2
PING lb.wordpress.com (192.0.78.12) 56(84) bytes of data.
64 bytes from 192.0.78.12: icmp_seq=1 ttl=54 time=15.3 ms
64 bytes from 192.0.78.12: icmp_seq=2 ttl=54 time=14.2 ms
64 bytes from 192.0.78.12: icmp_seq=3 ttl=56 time=14.4 ms
64 bytes from 192.0.78.12: icmp_seq=4 ttl=56 time=13.8 ms
^C
--- lb.wordpress.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 6007ms
rtt min/avg/max/mdev = 13.882/14.475/15.365/0.548 ms

Quando a combinação de teclas «Ctrl»+«C» é pressionada é enviado um sinal de término — SIGINT — para o processo que se encerrou e retornou o controle do terminal ao Bash.

Pausando um processo

Agora algo um pouco diferente, no mesmo terminal execute o vim, pressione «Insert» para entrar no modo de edição e digite cole este pequeno programa:

Daí pressione «Esc» para voltar ao modo de comando e salve o arquivo no disco com o seguinte comando:

:w counter.sh

Aí pressione «Ctrl»+«Z»!

$ vim
[1]+  Parado                  vim

Ao pressionar esta combinações de teclas foi enviado um sinal de pausa — SIGSTOP — para ele, a execução foi suspensa e o controle do terminal devolvido ao Bash.

O número “1” entre colchetes é o identificador, ou job spec², dele dentro desta sessão e não tem relação alguma com o PID do processo:

$ ps t
  PID TTY      STAT   TIME COMMAND
 4734 pts/2    Ss     0:00 bash
 6728 pts/2    T      0:00 vim
 6730 pts/2    R+     0:00 ps t

O job spec pode tanto ser referenciado apenas por seu valor numérico (1, 2 …) ou então prefixado com “%” (%1, %2 …) e exceto para terminá-los pode-se usar ambas as formas.

(²) Na documentação do Bash ele é as vezes grafado como JOB_SPEC.

Primeiro e segundo planos

Por enquanto deixemos o Vim sossegado para usar o programa que foi digitado nele:

$ bash counter.sh 1

Conte mais uma vez até dez antes de pressionar «Ctrl»+«Z» e o resultado será algo mais ou menos assim:

< 1 >< 2 >< 3 >< 4 >< 5 >< 6 >< 7 >< 8 >< 9 >< 10 >< 11 >< 12 >< 13 >
< 14 >< 15 >< 16 >< 17 >< 18 >^Z
[2]+  Parado                  bash counter.sh 1

Ele também foi pausado, como não é como já existe outro processo assim seu identificador é o %2 e querendo retornar a contagem basta usar o comando fg:

$ fg %2
bash counter.sh 1.
< 19 >< 20 >< 21 >< 22 >< 23 >< 24 >< 25 >< 26 >< 27 >< 28 >< 29 >^Z
[2]+  Parado                  bash counter.sh 1

É possível notar que o programa estava realmente parado já que a contagem recomeçou do ponto onde houve a primeira interrupção.

Usando o comando bgbackground — é possível deixá-lo executando em segundo plano:

$ bg %2
[2]+  bash counter.sh 1 &
< 30 >< 31 >...

Para alguns o sinal de “&” — ampersand — não é novidade e o que ele faz é informar ao Bash para não aguardar o programa terminar para retomar o controle do terminal. É justamente o que o comando bg faz, ele coloca o programa para executar em segundo plano, da mesma forma como se um “&” tivesse sido colocado no final da sua linha de comando.

Claro que o resultado será uma contagem sem fim ao qual nem «Ctrl»+«Z» ou «Ctrl»+«C» resolverão pois como o programa está em segundo plano ele não tem controle do terminal, logo não podemos enviar SIGSTOP ou SIGINT para ele. E a solução para este caso é colocá-lo em primeiro plano para poder pausá-lo/interrompê-lo.

Então, com calma e no meio da bagunça, escreva “fg %2”, pressione «Enter» e em seguida «Ctrl»+«Z».

...
< 157 >$ < 158 >< 159 >< 160 >f< 161 >g < 162 >%< 163 >2< 164 >< 165
>< 166 >< 167 >< 168 >< 169 >< 170 >
bash counter.sh 1
< 171 >< 172 >< 173 >< 174 >^Z
[2]+  Parado                 bash counter.sh 1

Uma diferença importante entre os comandos fg e bg é o fato de que o primeiro aceita apenas um job como parâmetro para o processo que ficará em primeiro plano enquanto que o outro pode receber uma lista com diversos jobs a colocar em segundo plano.

Listando os jobs em execução

Para saber quais são os processos sob controle do Bash basta usar o comando jobs:

$ jobs
[1]-  Parado                  vim
[2]+  Parado                  bash counter.sh 1

Para saber qual PID correspondente de cada job acrescente o parâmetro “-l” ao comando.

$ jobs -l
[1]-  6728                  Parado vim
[2]+  6732                  Parado bash counter.sh 1

Os sinais de “+” e “-” são, respectivamente, o último e penúltimo jobs que foram utilizados e um job marcado com o sinal de “+” será utilizado como padrão pelos comandos bg e fg.

Além do identificador numérico, ou job spec, é possível usar alguns atalhos:

  • %+ ou %% : O último job a ser utilizado;
  • %- : O penúltimo job a ser utilizado;
  • %«texto» : O job cujo comando começa com “texto”
  • %?«texto» : O job que contém “texto” em seu comando.

Aumentando um pouco a lista para servir de exemplo:

$ jobs
[1]+  Parado                  vim
[2]   Parado                  bash counter.sh 1
[3]   Parado                  nmon
[4]   Parado                  mc
[5]-  Parado                  bash ./counter.sh 2
[6]   Parado                  wget https://downloads.raspberrypi.org/
raspbian_lite_latest >/dev/null 2>&1

Neste caso %+ faz referência ao Vim (o último job a trocar de status), enquanto que %- para outra instância do programa de contagem (só que na cor verde ao invés de vermelho), %mc serve referencia o Midnight Commander e, finalmente, o %?raspian é a operação de download da última versão do Raspbian.

Encerrando os processos

Para encerrar um processo dentro do sistema de jobs do Bash também é usado o comando comando kill e a diferença está em ser possível usar o job spec (ou algum atalho) para identificar o processo.

Mas há um pequeno detalhe a se observar…

$ kill %5
[5]   Parado                  bash counter.sh 2
$ jobs %5
[5]   Parado                  bash counter.sh 2

…acontece que parado quer dizer literalmente parado, inclusive para se receber o aviso de encerramento.

$ fg %5
bash counter.sh 2
Terminado

Obviamente que este procedimento não é necessário para os jobs executando em segundo plano.

“Libertando” o processo

Lembrando que todos os processos executados desta forma atrelados a sessão do Bash e se esta for encerrada eles também o serão. Assim, antes de encerrar a conexão é bom encerrá-los ou, se for o caso, “liberá-los” para que continuem sendo executados. Por exemplo, para permitir que o download basta usar o comando disown:

$ bg %wget && disown %wget

E pronto, o processo continuará mesmo após o término da sessão tal qual como se tivesse sido executado através do comando nohup.

Finalizando…

Um uso bastante prático do controle de jobs é parar se manter o editor de textos parado com o arquivo de configuração/programa carregado e utilizar a combinação de teclas «Ctrl»+«Z» e o comando fg para rapidamente alternar entre editor e linha de comando quando se fazendo testes de configuração/depuração de código.

Claro, há ainda dois comandos do próprio Bash para o controle de jobs mas como eles não são usados diretamente na linha de comando e sim de dentro de scripts, ficarão para uma outra oportunidade… 🙂

Até!

Anúncios

Um comentário sobre “Controle de jobs do Bash

  1. Pingback: Controle de jobs nos scripts em Bash | giovannireisnunes

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s