2013-04-20 56 views
1

我正在構建一個Linux Shell,而我目前頭疼的是將命令行參數傳遞給fork/exec'ed程序和系統函數。用命令行參數分叉

當前所有輸入都在空格和新行上標記爲全局變量char * parsed_arguments。例如,輸入DIR/USA/FolderB中將被標記化如:

parsed_arguments[0] = dir 
parsed_arguments[1] = /usa/folderb 

parsed_arguments一切標記化完美;我現在的問題是,我只希望獲取一部分parsed_arguments,它排除了要在shell中運行的可執行文件的命令/第一個參數/路徑,並將它們存儲在一個名爲passed_arguments的新數組中。

所以在前面的例子DIR/USA/FolderB中

parsed_arguments[0] = dir 
parsed_arguments[1] = /usa/folderb 

passed_arguments[0] = /usa/folderb 
passed_arguments[1] = etc.... 

目前,我不會有這個,所以我希望有人能夠幫助我運氣好的話。以下是我迄今爲止的工作的一些代碼:

我如何試圖複製參數:

void command_Line() 
{ 

    int i = 1; 
    for(i;parsed_arguments[i]!=NULL;i++) 
    printf("%s",parsed_arguments[i]); 

} 

功能來讀取命令:

void readCommand(char newcommand[]){ 

printf("readCommand: %s\n", newcommand); 


//parsed_arguments = (char* malloc(MAX_ARGS)); 
// strcpy(newcommand,inputstring); 
    parsed = parsed_arguments; 
    *parsed++ = strtok(newcommand,SEPARATORS); // tokenize input 
    while ((*parsed++ = strtok(NULL,SEPARATORS))) 
     //printf("test1\n"); // last entry will be NULL 

     //passed_arguments=parsed_arguments[1]; 

    if(parsed[0]){ 
     char *initial_command =parsed[0]; 

    parsed= parsed_arguments; 
    while (*parsed) fprintf(stdout,"%s\n ",*parsed++); 
    // free (parsed); 
    // free(parsed_arguments); 

    }//end of if 


    command_Line(); 

}//end of ReadCommand 

分叉功能:

else if(strstr(parsed_arguments[0],"./")!=NULL) 
    { 
     int pid; 
     switch(pid=fork()){ 
     case -1: 
     printf("Fork error, aborting\n"); 
     abort(); 
     case 0: 
     execv(parsed_arguments[0],passed_arguments); 

     } 

    } 

enter image description here

這是我的shell當前輸出的內容。我第一次運行它時,它會輸出接近我想要的東西,但隨後的每次調用都會中斷程序。另外,每個額外的調用都會將分析的參數附加到輸出中。

這是原來的外殼生產什麼。再次,它接近我想要的,但不完全。我想省略該命令(即「./testline」)。

+0

每個命令的參數列表末尾是否有空指針? – 2013-04-20 00:14:04

+0

@JonathanLeffler它們都應該是字符串,最後應該有一個空指針。 – blutuu 2013-04-20 00:15:01

+0

好的;這是一個陷阱避免。在分叉代碼中,這是一個錯字嗎? 'execv(parsed_arguments [0],passed_arguments);'它應該是'execv(parsed_arguments [0],parsed_arguments);'?請注意,如果'execv()'返回,它將失敗,但代碼繼續讓失敗的子繼續。幾乎總是'exit()'或等效的'execv()'失敗後的等價物。並且也建議一條消息。 – 2013-04-20 00:18:18

回答

1

您的testline程序在您的工具箱中是明智的;我有一個類似的程序,我打電話給al(用於參數列表),打印它的參數,每行一個。它不打印argv[0]雖然(我知道它被稱爲al)。您可以輕鬆安排您的testline也跳過argv[0]。請注意,Unix約定是argv[0]是程序的名稱;你不應該試圖改變這種情況(你會對整個系統進行戰鬥)。

#include <stdio.h> 

int main(int argc, char **argv) 
{ 
    while (*++argv != 0) 
     puts(*argv); 
    return 0; 
} 

您的函數command_line()除了不必要地使用全局變量之外也是合理的。把全局變量想象成一種討厭的氣味(例如,H S);儘可能避免它們。它應該更像:

void command_Line(char *argv[]) 
{ 
    for (int i = 1; argv[i] != NULL; i++) 
     printf("<<%s>>\n", argv[i]); 
} 

如果你堅持C89,你需要聲明int i;外循環,並在閉環控制只使用for (i = 1; ...)。請注意,此處的打印將每個參數自行分隔開,並將其包含在標記字符中(<<>> - 更改以適應您的偏見和偏見)。可以跳過循環中的換行符(也許使用空格),然後在循環後添加一個換行符(putchar('\n');)。這使得更好,更接近通用調試例程。 (當我編寫「轉儲」功能時,我通常使用void dump_argv(FILE *fp, const char *tag, char *argv[])以便我可以打印到標準錯誤或標準輸出,幷包含標記字符串以標識轉儲的寫入位置。)

不幸的是,鑑於零碎的性質你的readCommand()功能,它是不可能連貫地批評它。註釋掉的行足以引起人們的關注,但是如果沒有你正在運行的實際代碼,我們無法猜測你正在做什麼問題或錯誤。如圖所示,它是等效於:

void readCommand(char newcommand[]) 
{ 
    printf("readCommand: %s\n", newcommand); 

    parsed = parsed_arguments; 
    *parsed++ = strtok(newcommand, SEPARATORS); 
    while ((*parsed++ = strtok(NULL, SEPARATORS)) != 0) 
    { 
     if (parsed[0]) 
     { 
      char *initial_command = parsed[0]; 
      parsed = parsed_arguments; 
      while (*parsed) 
       fprintf(stdout, "%s\n ", *parsed++); 
     } 
    } 

    command_Line(); 
} 

變量parsedparsed_arguments都是全局和可變initial_command被設置但不使用(又名「無意義」)。 if (parsed[0])測試不安全;你在前一行增加了指針,所以它指向了不確定的內存。

從表面上看,從屏幕截圖判斷,在第二次使用時,您沒有正確重置parsed_arguments[]和/或passed_arguments[]陣列;它可能是一個沒有被設置爲零的索引。不知道如何分配數據,很難知道你可能會做錯什麼。

我建議關閉這個問題,回到你的系統併產生一個最小的SSCCE。它應該在大約100行以下;它不需要執行execv()(或fork()),但應該使用上述command_Line()函數的變體來打印要執行的命令。如果此答案阻止您刪除(關閉)此問題,請使用您的SSCCE代碼對其進行編輯,並通過評論回覆此答案,以便我看到您已完成此操作。