Coprocessos em Bash – parte 1

coproc-1_abertura

Quando você executa um programa, pela linha de comando ou a partir de um script, o Bash se encarrega de executá-lo, aguardar a execução terminar, verificar se ela foi bem sucedida¹ e, sendo o caso, direcionar o resultado para a tela, arquivo etc…

No coprocesso² acontece algo diferente; já que o Bash o deixará executando em segundo plano e ao mesmo tempo redirecionará as entrada e saída padrão dele para descritores de arquivo que funcionarão como um canal de comunicação entre eles. É um recurso poderoso e ao mesmo tempo simples de implementar.

E nesta primeira parte, além de uma rápida introdução, a leitura da saída de um programa através de um coprocesso.

(¹) Ou em caso de erro notificar o corrido ou então desviar a execução para algum tratamento de exceções.

(²) Não inventei este nome! Eles são chamados assim mesmo pela documentação do Bash.

Introdução ao coprocesso

Começando com um exemplo muito simples utilizando o comando tail para exibir eventuais novas linhas dentro do arquivo “/var/log/kern.log”.

$ coproc tail -f /var/log/kern.log
[1] 15803

É possível verificar que o comando permanece em execução como um subprocesso, uma cortesia do parâmetro “-f”.

$ pstree -Anpu 15438 
bash(15438,giovanni)-+-tail(15803)
                     `-pstree(15886)

Aliás, para todos os efeitos ele é um job sendo gerenciado pelo Bash.

$ jobs
[1]+  Executando            coproc COPROC tail -f /var/log/kern.log &

O nome grifado em laranja — o COPROC — foi inserido por padrão já que criei algo chamado de coprocesso anônimo (é possível nomeá-los) e a partir deste é definido um array onde ficam registrados os descritores de arquivo utilizados por este coprocesso.

$ declare -p COPROC
declare -a COPROC='([0]="59" [1]="54")'

O primeiro elemento do array corresponde ao descritor do “STDOUT” enquanto que o segundo é do “STDIN”, eles podem ser lidos utilizando <&«descritor» — neste caso seria “<&59” mas como estes valores são dinâmicos é mais seguro usar o valor armazenado no array mesmo.

$ read LINE <&${COPROC[0]} ; echo $LINE
Oct 21 13:11:31 athena kernel: 2 sd 6:0:0:0: [sdb] Assuming drive cache
: write through

Mais algumas leituras, só para ver se funciona…

$ read LINE <&${COPROC[0]} ; echo ${LINE}
Oct 21 13:11:31 athena kernel: 2 sdb: sdb1 sdb2
$ read LINE <&${COPROC[0]} ; echo ${LINE}
Oct 21 13:11:31 athena kernel: 2 sd 6:0:0:0: [sdb] Attached SCSI remova
ble disk
$ read LINE <&${COPROC[0]} ; echo ${LINE}
Oct 21 13:11:32 athena kernel: 2 ISO 9660 Extensions: Microsoft Joliet 
Level 3

É como se o tail tivesse se transformado em um recurso do próprio Bash e o arquivo “/var/log/kern.log” uma variável cujo valor pudesse ser lido a qualquer momento — a tal comunicação assíncrona.

Como é um processo gerenciado pelo Bash, é possível finalizá-lo do mesmo modo.

$ kill %1
[1]+ Terminado coproc COPROC tail -f /var/log/kern.log
$ read LINE <&${COPROC[0]}
bash: ${COPROC[0]}: redirecionamento ambíguo

Ou deixá-lo ser encerrado quando a instância do Bash for terminada.

Sofisticando um pouco…

Aplicando a mesma ideia anterior para “colorizar” a saída do comando tail de um jeito pouco usual mas válido para uma demonstração…

O programa pede o nome de um arquivo a monitorar (ainda é um tail -f em execução) mas também precisa que a largura da tela seja múltipla de oito — já que é o número de cores a disposição e infelizmente não é possível pintar ½ caractere e o Bash não sabe direito tratar números não inteiros.

De resto é a mesma lógica do primeiro exemplo mas com a diferença de que já que se tem acesso a cada linha individual do arquivo que é enviado pelo tail ela é cortada em partes menores, cada uma colocada em uma cor diferente e daí impressa na tela.

Claro que um critério mais interessante poderia ser aplicado aqui para tornar este exemplo um pouco mais útil mas, como disse acima, é só uma demonstração…

Fim desta parte

E por enquanto é só, na próxima parte será a vez de interagir com o coprocesso enviando requisições pela entrada padrão dele e colhendo o resultado pela saída padrão. E também de chamá-los com qualquer outro nome além de COPROC… 🙂

Até!

Anúncios

Um comentário sobre “Coprocessos em Bash – parte 1

  1. Pingback: Coprocessos em Bash – parte 2 | 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