Linux管道和选择

问题描述

一个shell脚本

#!/bin/bash

while :
do
    echo "++stdout..";
    echo "++stderr.." >> /dev/stderr;
    sleep 1
done

和 c 程序

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
 
 
int main(int argc,char *argv[])
{
  pid_t pid; 
 
  int pipefd[2];
  int pipe_stderr[2];
 
  char parametr[32]; 
 
 
   if(argc != 2)
   {
        fprintf(stderr,"Niepoprawna liczba argumetNow procesu P \n");
        exit(EXIT_FAILURE);
   }
 
  /* pipe  
      pipe0 - write
      pipe1 - read
  */
  if(pipe(pipefd) == -1)
   {
    perror("pipe");
    exit(EXIT_FAILURE);
   }
 
  if(pipe(pipe_stderr) == -1)
   {
    perror("pipe");
    exit(EXIT_FAILURE);
   }
 
  sprintf(parametr,"%d",pipefd[0]); //convert - we want to use exec 
 
   pid = fork() ;
   if(pid < 0)
   {
    perror("fork!"); 
   }  
   else if(pid == 0)
   {
        puts("child");
        dup2(pipefd[1],STDOUT_FILENO); // write
        dup2(pipe_stderr[1],STDERR_FILENO); // write
        
        close(pipefd[0]);
        close(pipe_stderr[0]);
        execv(argv[1],&argv[1]); 
   }
   else{
        puts("parent");
        fd_set set;
        struct timeval timeout;
        int sel; 
        char buf;   

        close(pipefd[1]) ;  
        close(pipe_stderr[1]) ;  


        fcntl(pipefd[0],F_SETFL,O_NONBLOCK);
        fcntl(pipe_stderr[0],O_NONBLOCK);

        FD_ZERO(&set); 
        FD_SET(pipefd[0],&set); // READ
        FD_SET(pipe_stderr[0],&set); // READ


        timeout.tv_sec = 17; 
        timeout.tv_usec = 0; 

        while(1){
            puts("Select");  
            sel = select(FD_SETSIZE,&set,NULL,&timeout);
            if(sel < 0 )
            {
                perror("Select");  
            }
            else if(sel == 0)
            {
                printf("No communicate \n");
            }
            else{
                if(FD_ISSET(pipefd[0],&set)){
                    puts("PARENT_READ_STDOUT:");
                    while(1){
                        ssize_t ret = read(pipefd[0],&buf,1);
                        if(ret > 0){
                            write(STDOUT_FILENO,1);  
                        }else{
                            break;
                        }
                    }
                }

                if(FD_ISSET(pipe_stderr[0],&set)){
                    puts("PARENT_READ_STDERR:");
                    while(1){
                        ssize_t ret = read(pipe_stderr[0],1);
                        if(ret > 0){
                            write(STDERR_FILENO,1);  
                        }else{
                            break;
                        }
                    }
                }
            }
        }
   } 
}

输出

./main ./test.sh

parent
Select
child
PARENT_READ_STDOUT:
++stdout..
Select
PARENT_READ_STDOUT:
++stdout..
Select
PARENT_READ_STDOUT:
++stdout..
Select
PARENT_READ_STDOUT:
++stdout..
Select
PARENT_READ_STDOUT:
++stdout..
Select
PARENT_READ_STDOUT:
++stdout..
Select

stderr 输出到哪里去了??

解决方法

    timeout.tv_sec = 17; 
    timeout.tv_usec = 0; 

    while(1){

    FD_ZERO(&set); 
    FD_SET(pipefd[0],&set); // READ
    FD_SET(pipe_stderr[0],&set); // READ