2013-05-14 4 views
0

이것은 내 자신의 쉘에서 찾은 코드이다. 그것은 잘 작동하지만 내가 이해할 수없는 것은 코드의 파이프 섹션입니다.내 쉘에서 pipe()를 이해할 수 없다.

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 

char* cmndtkn[256]; 
char buffer[256]; 
char* path=NULL; 
char pwd[128]; 


int main(){ 

//setting path variable 
    char *env; 
    env=getenv("PATH"); 
    putenv(env); 
    system("clear"); 


printf("\t MY OWN SHELL !!!!!!!!!!\n "); 
printf("_______________________________________\n\n"); 

while(1){ 

    fflush(stdin); 
    getcwd(pwd,128); 
    printf("[MOSH~%s]$",pwd); 
    fgets(buffer,sizeof(buffer),stdin); 
    buffer[sizeof(buffer)-1] = '\0'; 

    //tokenize the input command line 
    char* tkn = strtok(buffer," \t\n"); 
    int i=0; 
    int indictr=0; 



     // loop for every part of the command 
     while(tkn!=NULL) 
     { 

      if(strcoll(tkn,"exit")==0){ 
       exit(0);     
      } 

      else if(strcoll(buffer,"cd")==0){ 
      path = buffer; 
      chdir(path+=3); 
      } 

      else if(strcoll(tkn,"|")==0){ 
      indictr=i; 
      } 

      cmndtkn[i++] = tkn; 
      tkn = strtok(NULL," \t\n"); 
     }cmndtkn[i]='\0'; 

// execute when command has pipe. when | command is found indictr is greater than 0. 
    if(indictr>0){ 

     char* leftcmnd[indictr+1]; 
     char* rightcmnd[i-indictr]; 
     int a,b; 

     for(b=0;b<indictr;b++) 
      leftcmnd[b]=cmndtkn[b]; 
     leftcmnd[indictr]=NULL; 

     for(a=0;a<i-indictr-1;a++) 
      rightcmnd[a]=cmndtkn[a+indictr+1]; 
     rightcmnd[i-indictr]=NULL; 

     if(!fork()) 
     { 
      fflush(stdout); 
      int pfds[2]; 
      pipe(pfds); 

       if(!fork()){ 
        close(1); 
        dup(pfds[1]); 
        close(pfds[0]); 
        execvp(leftcmnd[0],leftcmnd); 
       } 
       else{ 
        close(0); 
        dup(pfds[0]); 
        close(pfds[1]); 
        execvp(rightcmnd[0],rightcmnd); 
       } 
     }else 
      wait(NULL); 

//command not include pipe 

    }else{ 
     if(!fork()){ 
     fflush(stdout); 
     execvp(cmndtkn[0],cmndtkn); 

     }else 
      wait(NULL); 
    } 

} 

} 

이 전화의 목적은 공의 매개 변수() 종료 1의 의미와 호출이 무엇을 DUP하는 무엇이다()는 무엇입니까?

+0

이 (http://www.ccse.kfupm.edu.sa/~akbar/ICS431_031/LabExercises/Exercises.html) –

+0

[여기에서 쉬운 튜토리얼 일부를 가져옵니다 @ user315052 @xaxxon 나는'cd' 섹션을 이해하는데 문제가있다. 나는 왜 그것이 경로와 chdir (path + = 3)의 코드 세그먼트에 버퍼를 할당하는지 이해할 수 없다. 누군가 설명해 주시겠습니까 .. –

+0

@VirajLakshitha : 이와 같이 질문의 범위를 계속 확장 할 수는 없습니다. 꼭해야 할 일이 있다면 새로운 질문을하십시오. 그러나 다음 번에 자신이 직접 질문에 대답하려고 노력했음을 보여주기 위해 더 많은 노력을 기울이십시오. 그렇지 않으면, 그것은 진짜 질문이 아니지만 누군가가 당신을 위해 숙제를해야한다는 요구입니다. – jxh

답변

0

유닉스에서 dup() 호출은 가장 낮은 번호의 사용되지 않은 파일 설명자를 사용합니다. 따라서 dup()을 호출하기 전에 close(1)은 파일 설명자 1을 사용하기 위해 dup()을 강제 변환합니다. 마찬가지로 close(0).

따라서, 에일리어싱 stdout (디스크립터 1 콘솔 출력에 사용되는 파일) 및 stdin 용 파이프의 판독 끝 파이프의 쓰기 단부를 사용하는 방법을 얻는 것이다 (파일 기술자 0에 사용 콘솔 입력).

코드가 dup2()으로 표시 될 수 있습니다. ls | sort 작품, 귀하의 질문은 dup() 시스템 호출이되고있는 이유에 한정되지 않고, 방법에 대한 질문에서


dup2(fd[1], 1); /* alias fd[1] to 1 */ 

. 귀하의 질문은 실제로 유닉스의 파이프가 어떻게 작동하는지, 쉘 명령 파이프 라인이 어떻게 작동하는지입니다.

유닉스의 파이프는 쓰기 가능한 디스크립터의 데이터 쓰기가 읽기 가능한 디스크립터에서 데이터를 읽을 수 있도록하는 한쌍의 파일 디스크립터이다. pipe() 호출은 배열에서이 쌍을 반환하며 첫 번째 배열 요소는 읽을 수 있고 두 번째 배열 요소는 쓸 수 있습니다. 유닉스에서

, exec() 어떤 종류의 뒤에 fork()가 새로운 프로세스 (예 : system() 또는 프로세스를 만들 popen() 같은 다른 라이브러리 호출이, 거기를 생산하는 유일한 방법입니다,하지만 그들은하에 exec()fork()를 호출 할 후드). fork()은 하위 프로세스를 생성합니다. 자식 프로세스는 호출에서 0의 반환 값을보고 부모는 자식 프로세스의 PID가 아닌 0이 아닌 반환 값을 보거나 오류가 발생했음을 나타내는 -1을 봅니다.

하위 프로세스는 상위의 복제본입니다. 이것은 자식이 변수를 수정할 때 자신의 프로세스에있는 변수의 복사본을 수정하고 있음을 의미합니다. 부모는 원본 사본을 가지고 있기 때문에 부모는 수정 된 것을 보지 못합니다. 그러나 파이프를 형성하는 파일 설명자의 이중화 된 쌍을 사용하여 하위 프로세스가 상위 프로세스가 서로 통신 할 수 있습니다.

그래서, ls | sort이 산란되는 두 프로세스이며 ls 작성한 출력 sort가 입력으로서 판독되고 있음을 의미한다. 두 프로세스는 두 개의 자식 프로세스를 생성하기 위해 fork()에 대한 두 번의 호출을 의미합니다. 하나의 하위 프로세스는 exec() ls 명령이고, 다른 하위 프로세스는 exec() sort 명령입니다. 파이프는 프로세스가 서로 이야기 할 수있게하기 위해 파이프 사이에 사용됩니다. ls 프로세스는 파이프의 쓰기 가능한 끝에 씁니다. sort 프로세스는 파이프의 읽을 수있는 끝에서 읽습니다.

ls 프로세스는 close(1) 발행 후 dup() 호와 파이프의 단부에 쓰기 기록 강요된다. sort 프로세스는 호출 (close(0))으로 파이프의 읽을 수있는 끝을 읽도록 강제됩니다. 또한

가, 파이프 파일 설명을 닫으 close() 호출이 ls 프로세스가 쓰기 가능한 FD에 열린 참조가 할 수있는 유일한 프로세스가 있는지 확인하는 데 사용됩니다,하여 sort 프로세스는이 유일한 과정이다 읽을 수있는 fd에 대한 열린 참조. 이 단계는 ls 종료 후에 fd의 쓰기 가능한 끝을 닫고 sort 프로세스가 결과적으로 EOF를 볼 것으로 예상되므로 중요합니다. 그러나 다른 프로세스가 여전히 쓰기 가능 fd를 ​​열어두면이 문제는 발생하지 않습니다.

+0

답변 해 주셔서 감사합니다. 내가 'ls |'명령을 입력하면 어떻게 될지 설명해 주시겠습니까? 정렬 '. 나는 'ls'의 출력이 '정렬'에 대한 입력이 될 것이라는 것을 알고 있습니다. 그러나 어떻게 처형 될 것인가 ?? 나는 'ls'와 'sort'명령이 두 개의 다른 배열에 저장되어 있기 때문에 이것을 묻습니다. 블록에있을 때 'execvp'를 사용하여 관련 else 블록을 사용하여 어떻게 실행할 수 있습니까? @ xaxxon –

0

http://en.wikipedia.org/wiki/Standard_streams#Standard_input_.28stdin.29

표준 입력 0

은 표준 출력 파일 기술자에게! 포크 부 1.

이고, 처리는 다음 표준 출력 종료 pfds에 DUP 호출 파일 기술자에게 [1] 어느 항 :

http://linux.die.net/man/2/dup

는 상기 지정된 파일 기술자의 중복을 작성합니다 가능한 가장 낮은 위치는 방금 닫히고 (그리고 stdin이 아직 닫혀 있지 않기 때문에) 1이 될 것입니다. 이것은 stdout에 보내지는 모든 것이 실제로 pfds [1]로 갈 것이라는 것을 의미합니다.

그래서 기본적으로 서로 통신하기 위해 두 개의 새로운 프로세스를 설정하고 있습니다. ! fork 섹션은 데이터를 stdout (파일 설명자 1)로 보내고, 부모 (else 블록)는 stdin을 닫습니다. 따라서 stdout에서 읽으려고 할 때 실제로 pfds [0]에서 읽습니다.

각 프로세스는 프로세스가 분기 한 파일에 대한 열린 핸들이 두 개이므로 사용하지 않는 pfds에서 파일 설명자를 닫아야합니다. 각 프로세스는 이제 왼쪽/오른쪽 cmnd로 실행되지만 새 프로세스에 대해 새로운 stdin 및 stdout 매핑이 유지됩니다.

두 번 여기에 설명 분기 : Why fork() twice

+0

답변 해 주셔서 감사합니다. 내가'ls | '명령을 입력하면 어떻게되는지 설명해 주시겠습니까? 정렬'. 나는'ls'의 출력이'sort'에 대한 입력이 될 것이라는 것을 압니다. 그러나 어떻게 처형 될 것인가 ?? 나는'ls'와'sort' 명령이 두 개의 다른 배열에 저장되어 있기 때문에 이것을 묻습니다. 블록과 if 블록에있을 때'execvp'를 사용하여 어떻게 실행시킬 수 있습니까? –

+0

'ls'는 결과를 stdout에 씁니다. 맞습니까?'sort'는 stdin에서 읽습니다. 이제는 'ls'가 실제로 파이프의 한쪽 끝에 쓰고 있기 때문에 '정렬'은 표준 입력을 읽고 있기 때문에 연결되었습니다. – xaxxon

+0

파이프를 실행할 때 두 개의'fork()'시스템 호출을 사용해야하는 이유를 설명 할 수 있습니까? –

관련 문제