2013-05-14 91 views
0

這是我爲我自己的shell找到的代碼。它工作正常,但我不明白的是代碼的管段。無法理解我自己的shell中的管道()

#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); 
    } 

} 

} 

什麼是呼叫的目的,關閉()爲0的參數和1意味着又是什麼調用DUP()呢?

+0

[從這裏容易教程]得到一些(http://www.ccse.kfupm.edu.sa/~akbar/ICS431_031/LabExercises/Exercises.html) – 2013-05-14 07:34:13

+0

@ user315052 @xaxxon我在理解'cd'部分時也有問題。我不明白爲什麼它將緩衝區分配給'chdir(path + = 3)'的路徑和代碼段。有人可以請解釋它.. – 2013-05-14 18:23:26

+0

@VirajLakshitha:你不能像這樣繼續擴大你的問題的範圍。如果您必須提出一個新問題,但下次更努力證明您已嘗試自己回答問題。否則,這不是一個真正的問題,而是要求某人爲你做功課。 – jxh 2013-05-15 05:38:03

回答

0

在Unix上,dup()調用使用編號最小的未使用文件描述符。所以,調用dup()之前的close(1)是強制dup()使用文件描述符1.同樣爲close(0)

因此,別名是使用stdout(文件描述符1用於控制檯輸出)的管道的寫入結束的過程,並且stdin(文件描述符0)的管道的讀取結束用於控制檯輸入)。

代碼可能已用dup2()代替更清楚地表達。

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

從你如何ls | sort的作品,你的問題並不侷限於爲什麼dup()系統調用正在取得問題。你的問題實際上是Unix中的管道是如何工作的,以及shell命令管道是如何工作的。

Unix中的管道是一對文件描述符,它們的相關之處在於,在可寫描述符上寫入數據允許從可讀描述符中讀取數據。 pipe()調用將返回一個數組中的第一個數組元素是可讀的,第二個數組元素是可寫的。

在Unix下,fork()其次是某種exec()是產生一個新的進程(還有其他庫調用,如system()或創建進程popen()的唯一途徑,但他們稱fork(),做一個exec()下罩)。 A fork()產生一個子進程。子進程從調用中看到0的返回值,而父進程則看到一個非零返回值,該值是子進程的PID,或表示發生了錯誤的-1

子進程是父進程的副本。這意味着當一個孩子修改一個變量時,它正在修改駐留在它自己的進程中的變量的副本。父母沒有看到修改發生,因爲父母有原始副本)。但是,可以使用構成管道的重複的一對文件描述符來允許子進程與其父進程進行通信。

因此,ls | sort意味着有兩個進程正在生成,ls寫入的輸出正在被讀取爲sort的輸入。兩個進程意味着兩個調用fork()來創建兩個子進程。一個子進程將exec()命令ls,其他子進程將exec()命令sort命令。在它們之間使用管道以允許進程相互交談。 ls進程寫入管道的可寫端,sort進程從管道的可讀端讀取。

ls進程在發出close(1)後被強制寫入管道的可寫入端,並調用dup()調用。 sort過程被強制爲在close(0)之後用dup()調用讀取管道的可讀端。

此外,關閉管道文件描述符close()調用用於確保該ls過程是有一個開放的參考寫入FD唯一的過程中,該sort過程是有一個唯一的過程開放引用可讀的fd。該步驟很重要,因爲ls退出後將關閉fd的可寫結束,並且sort進程將期望看到EOF。但是,如果其他進程仍然有可寫的fd打開,則不會發生這種情況。

+0

感謝您的回答。你能解釋一下如果我輸入命令'ls |會發生什麼?排序'。我知道'ls'的輸出將會是'排序'的輸入。但是它將如何被執行?我問這是因爲'ls'和'sort'命令存儲在兩個不同的數組中。當他們在if塊和相關的其他塊中時,它們如何使用'execvp'來執行。 @xaxxon – 2013-05-14 16:33:44

0

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

標準輸入是文件描述符0

stdout是文件描述符1.

在!叉部分,該處理標準輸出關閉然後調用工藝流程圖DUP [1],其根據:

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

創建在指定的文件描述符的副本最低的可用位置,它將是1,因爲它剛剛關閉(並且stdin尚未關閉)。這意味着發送到標準輸出的所有內容都將真正轉到pfds [1]。

因此,基本上,它建立了兩個新的進程來相互交談。 !fork部分用於將數據發送到stdout(文件描述符1)的新子節點,父節點(else塊)關閉stdin,因此它在嘗試從stdout讀取時從pfds [0]讀取數據。

每個進程必須關閉它不使用的pfds中的文件描述符,因爲現在該進程已經分叉了,所以文件有兩個打開的句柄。每個進程現在執行到左/右 - cmnd,但新的進程保留新的stdin和stdout映射。

分叉兩次在這裏解釋:Why fork() twice

+0

感謝您的回答。你能解釋一下如果我輸入命令'ls |會發生什麼排序'。我知道'ls'的輸出將成爲'sort'的輸入。但是它將如何被執行?我問這是因爲'ls'和'sort'命令存儲在兩個不同的數組中。當它們在if塊和相關的else塊中時,它們如何使用'execvp'來執行。 – 2013-05-14 19:10:31

+0

'ls'將結果寫入標準輸出,對吧?從stdin讀取'sort'。現在他們被連接起來,因爲'ls'實際上正在寫入'sort'正在讀取stdin的管道的一端。 – xaxxon 2013-05-14 22:20:58

+0

你可以解釋一下,爲什麼我應該在執行管道時使用兩個'fork()'系統調用? – 2013-05-15 04:59:27