ComunicacaoComPipes

Comunicação com Pipes

Este artigo destina-se a fazer uma introdução sobre o que são pipes e como programá-los em Python, explorando esse recurso poderoso em programação de ferramentas interligáveis.

Introdução

Pipe (traduzido literalmente para o português como "cano") é o famoso redirecionamento de entrada/saída de um programa para o outro. O exemplo mais comum conhecido, tanto em ambientes Unix como Windows, é controlar a saída de um programa que fornece várias páginas de texto usando o more para pausar ao final de cada página:

> ls | more

O que acontece é que o programa ls lista o conteúdo do diretório e, através do pipe (|), direciona sua saída como entrada para o próximo programa, more. O programa more detecta a última linha do console e para temporariamente a entrada de dados. Ao digitar uma tecla, more continua a leitura da entrada.

Cada processo em execução possui basicamente dois canais de comunicação iniciais: a entrada padrão e a saída padrão. Quando um programa é iniciado via console, o sistema operacional se encarrega em conectar os dispositivos teclado e vídeo respectivamente a esses dois canais para que o usuário possa interagir com ele. Mas a capacidade de usar outros programas como entradas e saídas possibilita grande flexibilidade de automação de procedimentos.

Para se ter uma idéia sobre a utilidade deste recurso, usar o shell (console) sem ele seria muito mais limitante.

O Módulo popen2

O módulo popen2 fornece opções de acordo com o estilo de programação desejado, se você escolher um estilo de programação mais procedural, as funções popen2, popen3 e popen4 podem ser usadas de acordo com as suas necessidades. Para trabalhar com objetos, usa-se as classes Popen3 e Popen4 (observe os nomes começando em maiúsculas). Infelizmente estas classes só estão disponíveis em ambiente Unix.

As Funções popen2, popen3 e popen4

As funções popen2, popen3 e popen4 executam um programa paralelamente (isto é, sem esperar ele acabar para continuar) e tornam possível que se comunique com o processo filho criado através daqueles pipes apresentados anteriormente. Esses pipes são recebidos como retorno das funções popen. As várias funções popen oferecem possibilidades de combinação:

popen2(cmd[,bufsize[,mode]])

popen3(cmd[,bufsize[,mode]])

popen4(cmd[,bufsize[,mode]])

O argumento opcional bufsize indica o tamanho interno do buffer (área de transferência, onde dados são guardados temporariamente), já o modo indica se os canais de comunicação devem ser lidos como texto ('t') ou binário ('b') e só fazem sentido em ambiente Windows.

As tuplas que essas funções retornam contém objetos do tipo file (arquivo) e são os canais de comunicação para enviar e receber dados. Por exemplo: a função popen2 retorna (child_stdin, child_stdout), o que quer dizer que a função retorna uma tupla, do qual o primeiro objeto é o canal de saída do programa executado (stdout - standard output) e o segundo objeto, o canal de entrada (stdin - standard input).

O objeto child_stderr representa a saída de erro de um programa (e este é geralmente o vídeo também), mas sua importância é maior para depuração de programas, caso eles dêem erros. O objeto child_stdout_and_stderr envia tanto a saída quanto o erro pelo mesmo canal e também tem maior importância na depuração de um programa.

Um Exemplo

Vamos simular o uso da linha abaixo, quando digitada no shell do sistema operacional GNU/Linux:

~$ ls | sort | head

O que significa pegar a lista de arquivos do diretório (ls), colocamos em ordem alfabética (sort) e pegamos as 10 primeiras entradas (head) já em ordem. Estamos usando redirecionamento: a entrada de cada processo é a saída do outro. O equivalente em Python seria abrir o processo com popen e ler de cada um e escrever para o próximo:

import popen2

# Abrimos todos os programas ls, sort e head em paralelo.
output_ls, input_ls = popen2.popen2('/bin/ls')
output_sort, input_sort = popen2.popen2('/bin/sort')
output_head, input_head = popen2.popen2('/bin/head')

# Não precisamos da entrada do programa ls, só da saída
input_ls.close()

# Lemos a saída do programa ls e colocamos na varíavel text
text = output_ls.readlines()

# Fechamos todos os canais de ls, terminando o processo.
output_ls.close()

# Enviamos text para o programa sort.
input_sort.writelines(text)

# E enfim fechamos a entrada de sort.
input_sort.close()

# Depois de processado, pegamos a saída de sort.
text = output_sort.readlines()

# Encerramos o processo sort.
output_sort.close()

# Enviamos text para o programa head.
input_head.writelines(text)

# Fechamos a entrada do programa head.
input_head.close()

# Imprimimos na tela a saída do programa head.
print str().join(output_head.readlines())

# Encerramos o último processo.
output_head.close()

As Classes de popen2

As classes Popen3 e Popen4 só funcionam em ambiente Unix, como foi dito antes, e elas fornecem algumas vantagens, como a possibilidade de usar as funções do sistema wait e poll para trabalhar com os estados finais dos processs filhos retornados. Estas funções estão fora do escopo deste documento e não serão tratados aqui. No demais, os objetos file do processo criado são representados pelos atributos fromchild (saída do processo), tochild (entrada do processo) e childerr (saída de erro do processo).

Últimas Palavras

Bom, este foi um artigo um tanto longo e trabalhoso, mas espero que ele ajude as pessoas novas em Python e também em programação em ambientes Unix a entender essa poderosa ferramenta que eles tem em suas mãos. =)


PedroDeMedeiros

ComunicacaoComPipes (editada pela última vez em 2008-09-26 14:05:58 por localhost)