2012-09-26 7 views
1

그래서 C 프로젝트를 사용하여 기본 UNIX 셸을 만드는 과정이 끝났습니다. 이제는 프로그램의 많은 부분을 끝 냈지만 이제는 파이핑을 정복하려고합니다. 나는 특별히 파이프 수를 으로 처리 할 수있는 프로그램을 만들고 싶습니다.주어진 배열의 유닉스 명령

어떤 이유로 든 내 코드가 특정 행 (// DIES 여기에)이라고 표시되어 멈추고 그 이유를 알 수 없습니다.

//the contents of args[0] is {"ls","-l","-o"} 
//the contents of args[1] is {"wc","-l"} 

int pipefd[2]; 

pipe(&pipefd[0]); // Error check! 

fflush(stdout); 
for (i = 0; i < commands; i++){ 
    int pid = fork(); 

    if (pid == 0){ 

     int command_no = i; 
     int prev_pipe = ((command_no - 1) % 2) * 2; 
     int current_pipe = (command_no % 2) * 2; 
     printf("\ncmd %d: prev pipe %d, curr pipe %d\n\n", i, prev_pipe, current_pipe); 
     fflush(stdout); 

     // If current command is the first command, close the 
     // read end, else read from the last command's pipe 
     if (command_no == 0){ 
      close(pipefd[0]); 
     } 
     else{ 
      dup2(pipefd[prev_pipe], 0); 
      close(pipefd[current_pipe]);      
     } 

     // If current command is the last command, close the 
     // write end, else write to the pipe 
     if (command_no == commands - 1){ 
      close(pipefd[current_pipe + 1]);      
     } 
     else{ 
      dup2(pipefd[current_pipe + 1], 1); //DIES HERE 
     } 
     // printf("Here?\n\n"); 
     execvp(*args[i], args[i]); 
     fprintf(stderr, "Failed to exec: %s (%d: %s)\n", arrayOfCommands[i], errno, strerror(errno)); 
     _exit(1); 
    } 
} 

이 어떤 도움에 감사드립니다 :

는 여기에 지금까지 가지고있는 코드입니다! :)

+0

execvp()가 실패하면 (0이 아닌 숫자) 종료해야합니다. 0은 유닉스에서 성공을 보여주는 데 사용됩니다. – Scooter

+1

하나의 프로세스 그룹에 모든 파이프 된 프로세스를 두는 것을 잊지 마십시오 (첫 번째 프로세스를 프로세스 그룹 리더로 함). 이렇게하면 전체 그룹이 끝날 때까지 기다릴 수 있습니다 ('waitpid'또는 더 나은 'waitid'기능 참조). 나는 bash 소스 코드를 살펴볼 것을 제안한다. 뿐만 아니라 디버깅 모드에서 bile을 실행하고 실행 중에 디버깅하면 많은 것들을 볼 수 있습니다. – sirgeorge

답변

1

내가 보는 주된 문제는 pipe()이 루프 바깥에 있다는 것입니다. 모든 프로세스 쌍 사이에 새로운 pipe()이 필요합니다. 귀하의 질문에 대한 의견도 좋은 지적을합니다.

나는 대학에서 몇 년 전에 쉘을 썼고, 여기 내 코드에서 비슷한 루프가있다. 지금은 많이 달라질 것이지만, 아마도 당신에게 유용 할 것입니다.

for (i = 0; i < iNumPipes; ++i) { 
      if (i == iNumPipes - 1) { 
        /* this is the last command 
        */ 
        p[1] = fdOutput; 
        p[0] = -1; 
      } else if (-1 == pipe(p)) { 
        perror("pipe"); 
        exit(1); 
      } 

      switch (iPid = fork()) { 
      case -1: 
        perror("fork"); 
        exit(1); 
      case 0: 
        close(0); 
        dup2(fdInput, 0); 
        close(fdInput); 

        close(1); 
        dup2(p[1], 1); 
        close(p[1]); 

        if (-1 != fdErr) { 
          close(2); 
          dup2(fdErr, 2); 
          close(fdErr); 
        } 

        pc = SearchPath(pppcAvs[i][0]); 
        execve(pc, pppcAvs[i], ppcEnv); 
        perror(pc); 
        _exit(-1); 
      default: 
        close(fdInput); 
        close(p[1]); 
        fdInput = p[0]; 
      } 

    } 
+0

대단하군요! fdErr이 무엇인지 공유해 주시겠습니까? 알아내는 데 어려움이 있습니다. –

+0

실제로 fdOutput, fdInput 및 fdErr이 정의되는 방법을 공유하는 것이 더 좋을까요? –

+0

그들은 모두 파일 설명자입니다 (따라서 헝가리 표기법을 사용 했으므로'fd' 접두어로 사용되었습니다). 그래서 그들은'int'입니다. 셸은'stderr'를위한 특별한 리다이 렉팅 룰을 가졌으므로'fdErr'은 "글로벌"에러 리디렉션입니다. 'fdOutput'과'fdInput'은 체인의 홉을 연결합니다. 이 루프 전에 커맨드 라인에서 파일 리다이렉트가 발생하지 않는 한'dup (0)'과'dup (1)'로 설정됩니다. –