[Python-es] subprocess.popen, capturar stdout :)
Oswaldo Hernández
listas en soft-com.es
Vie Nov 2 15:29:54 CET 2007
Oswaldo Hernández escribió:
> Rafael Villar Burke escribió:
>
>> Si no es muy extensa (me imagino que no), incluso podría ir como adjunto
>> a la lista, para que quede en los archivos.
>> Seguro que a mucha gente le interesa.
>>
>
> No se si la lista permite archivos adjuntos, si no llega envio otro
> mensaje con codigo en el cuerpo del mensaje.
>
No ha llegado, aqui va el codigo:
/**********************************************************
pipe.c
02-11-07
Oswaldo Hernández
oswaldo en soft-com.es
Captura stdout y stderr de la aplicación a ejecutar y los envia
por lineas a la salida std añadiendo el prefijo 'Out:' o 'Err:'
dependiendo de donde se haya capturado.
Despues del envio de cada linea realiza un flush para asegurar
que no quede en el buffer.
Compilación:
gcc pipe.c -o pipe
Uso:
pipe aplicacion parametro parametro ...
TODO:
Añadir parametros para configurar/ampliar funcionalidad:
/NOPRE -> no enviar prefijos con los mensajes
/IN -> crear pipe para reenviar stdin a la aplicacion
y establecer comunicacion bidireccional
***********************************************************/
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#define BUFZISE 1024
typedef struct {
char buf[BUFZISE];
int bytes;
} buffer;
void envialinea(buffer *buf, char *prefijo);
int main(int argc, char** argv)
{
pid_t pid;
int rv;
int outpipe[2];
int errpipe[2];
if (argc <= 1) {
printf("Parametros insuficientes, debe especificar la aplicacion a ejecutar.\n");
exit(1);
}
/* Setup communication pipeline first */
if(pipe(outpipe) || pipe(errpipe)){
fprintf(stderr,"Pipe error!\n");
exit(1);
}
/* Attempt to fork and check for errors */
if( (pid=fork()) == -1){
fprintf(stderr,"Fork error. Exiting.\n"); /* something went wrong */
exit(1);
}
if(pid){
int retval;
buffer bout;
buffer berr;
bout.bytes = 0;
berr.bytes = 0;
close(outpipe[1]);
close(errpipe[1]);
// lecturas no bloqueantes
fcntl(outpipe[0], F_SETFL, O_NONBLOCK);
fcntl(errpipe[0], F_SETFL, O_NONBLOCK);
// buffer de salida
setvbuf(stdout,(char*)NULL,_IONBF,0);
// bucle de lecturar hasta que finaliza la aplicacion
while(1) {
retval = read(outpipe[0], bout.buf+bout.bytes, BUFZISE-bout.bytes);
if (retval > 0) {
bout.bytes += retval;
envialinea(&bout,"Out");
}
retval = read(errpipe[0], berr.buf+berr.bytes, BUFZISE-berr.bytes);
if (retval > 0) {
berr.bytes += retval;
envialinea(&berr,"Err");
}
if (waitpid(pid, &rv, WNOHANG) != 0)
break;
}
// salida con el codigo de retorno de la aplicacion
exit(rv);
}
else{
char cmd[512];
int x;
// stdout y stderr sin buffer
setvbuf(stdout,(char*)NULL,_IONBF,0);
setvbuf(stderr,(char*)NULL,_IONBF,0);
// asignar stdout y stderr a los pipes
dup2(outpipe[1],1);
dup2(errpipe[1],2);
close(outpipe[0]);
close(errpipe[0]);
// ejecutar aplicacion
cmd[0] = 0;
for (x = 0; x < argc; x++) {
strcat(cmd, argv[x]);
strcat(cmd, " ");
}
// OjO, el primer parametro de argv soy yo
argv ++;
execvp(argv[0], argv);
// Error de ejecucion
fprintf(stderr,"execl Error! %d", errno);
exit(1);
}
return 0;
}
/*****************************************
analisis del buffer de entrada,
busca '\n', si lo encuentra extrae la linea
y la envia, caso contrario espera a que se
complete.
*****************************************/
void envialinea(buffer *buf, char *prefijo)
{
int x;
int encontrado;
// fin de cadena
buf->buf[buf->bytes] = 0;
while(1) {
encontrado = 0;
// buscar fin de linea
for (x = 0; x < buf->bytes; x++) {
if (buf->buf[x] == '\n') {
encontrado = x;
break;
}
}
if (encontrado) {
// enviar linea
buf->buf[encontrado] = 0;
printf("%s:%s\n", prefijo, buf->buf);
fflush(stdout);
// desplazar el resto al inicio del buffer
encontrado ++;
strcpy(buf->buf, buf->buf + encontrado);
buf->bytes -= encontrado;
}
else
break; // no hay lineas en el buffer
}
}
--
*****************************************
Oswaldo Hernández
oswaldo (@) soft-com (.) es
*****************************************
Más información sobre la lista de distribución Python-es