domingo, 23 de setembro de 2012

Desafio em C no Unix – Simulando o comando: cat | more


Considere um programa que apresenta a sua saída página por página. Ao invés de reinventar a paginação feita por vários utilitários do sistema Unix, desejamos chamar o paginador favorito do usuário (more, less, …). Faça um programa que use um pipe para redirecionar a saída para o paginador. O programa recebe o nome do arquivo a ser mostrado como entrada e repassa linha a linha deste arquivo a um processo filho através de um pipe. O processo filho irá executar o paginador.

Vamos inicialmente conceituar alguns comandos a serem utiliados:

more filtro de arquivo para leitura e visualização em monitores

Descrição: é um filtro para  paginar textos em uma tela de cada vez. Este paginador é simples. Os usuários devem perceber que o comendo less (1) prover mais de emulação (1) e mais melhorias.

less - O oposto do more

Descrição: less é um programa semelhante ao more , mas que permite o movimento para trás no arquivo, bem como o movimento para frente. Além disso, menos não tem que ler o arquivo de entrada inteiro antes de começar, portanto, com grandes entradas começa-se mais rápido do que editores de texto como vi.

pipe - Cria um pipe

Descrição

O Pipe, utilizado através do comando “|” permite que a saída de um comando seja diretamente utilizado em outro comando. O pipe tem seu nome inspirado nos tubos (pipes), de transporte de fluídos. A ideia do PIPE é encadear um conjunto de processos, de modo que a saída de cada um seja a entrada do seguinte. 

 O exemplo abaixo mostra claramente como utilizar o Pipe:


$ ls -l | grep imagem | sort -r
O primeiro comando ls -l lista o conteúdo do diretório em formato longo, a seguir o comando Pipe faz com que a saída do primeiro comando entre no segundo comando, grep imagem que procura na listagem do diretório qualquer arquivo que possua a palavra imagem, por final, a saída do comando grep imagem é utilizada no comando sort -r que faz a classificação de forma crescent
Conding in C

 Vamos ao Primeiro Código:  

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/wait.h>
 int main(int argc, char *argv[]) {
 int fd[2], pid1, pid2;
 char *my_program1[3] = {“/bin/cat”, argv[1], NULL};
 char *my_program2[2] = {“/bin/more”, NULL};
 pipe(fd);
 if((pid1 = fork()) == 0) {
 close(STDOUT_FILENO);
 dup(fd[1]);
 close(fd[0]); close(fd[1]);
 execv(my_program1[0], my_program1);
 }
 if((pid2 = fork()) == 0) {
 close(STDIN_FILENO);
 dup(fd[0]);
 close(fd[0]); close(fd[1]);
 execv(my_program2[0], my_program2);
 }
 close(fd[0]); close(fd[1]);
 waitpid(pid1, NULL, 0);
 waitpid(pid2, NULL, 0);
 return 0;
 }

Executando
Para executar o código, não se esqueça de gerar a compilação do arquivo, como por exemplo:
gcc -o CatMore CatMore.c
Após, para execução, o programinha espera que você passe o nome do arquivo que deve ser lido por parâmetro, por exemplo:
./CatMore CatMore.c
O resultado disso será a leitura do próprio arquivo CatMore.c.

Explicação do Primeiro Código
Este código está bem simples. Foi a primeira versão que fiz para atender ao problema, porém ainda não está completamente correto. Se vocês repararem no enunciado, tem o seguinte detalhe: ‘e repassa linha a linha deste arquivo a um processo filho através de um pipe’, o que quer dizer que não podemos usar o cat para ler o arquivo desejado, devemos fazer o código que percorrerá linha a linha do arquivo passado por parâmetro e jogar no pipe para que o more possa lê-lo da forma desejada.


 Então, Vamos ao Segundo Código:  
 #include <unistd.h>  
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <string.h>  
 #define MAXLINE 4096  
 int main(int argc, char *argv[]) {  
 int n, fd[2];  
 pid_t pid;  
 char line[MAXLINE];  
 char *my_program[2] = {“/bin/more”, NULL};  
 FILE *arquivo;  
 if (pipe(fd) < 0) {  
 fprintf(stderr, “pipe error”);  
 }  
 if ((pid = fork()) < 0) {  
 fprintf(stderr, “fork error”);  
 } else if (pid > 0) {  
 /* parent */  
 close(fd[0]);  
 arquivo = fopen(argv[1],”r”);  
 while (fgets(line, MAXLINE, arquivo) != NULL)  
 {  
 write(fd[1], line , (strlen(line)));  
 }  
 fclose(arquivo);  
 close(fd[1]);  
 waitpid(pid, NULL, 0);  
 exit(0);  
 } else {  
 /* child */  
 close(STDIN_FILENO);  
 dup(fd[0]);  
 close(fd[1]);  
 execv(my_program[0], my_program);  
 }  
 return 0;  
 }  




Fontes:

http://www.vivaolinux.com.br/dica/Pipes-no-Linux; http://jairofranchi.wordpress.com/2011/03/24/utilizando-o-comando-pipe-linux/ http://www.quaddro.com.br/blog/programando-em-ansi-c/estudando-bibliotecas-de-c-stdio-h
http://joelsonlucena.wordpress.com/2012/09/19/desafio-em-c-no-unix-simulando-o-comando-cat-more/






Nenhum comentário:

Postar um comentário