2014-02-22 55 views
1

使用fork和execvp函數從stdin行運行命令,製作一個簡單類型的shell。實現一個簡單的shell

但是,像ls這樣的工作,但不是ls -all -S。 它將執行ls,但什麼都不會被打印ls -all

唯一的想法,我能想出的是,有一個「\ n」某處的命令,但我不知道怎麼把它弄出來甚至它在哪裏......

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <time.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
//Libs ^^^^ Defs vvvvvvvv 
#define comlen 4096      //Max command length 
#define comarg 32    //Max argument length 

int main(int argc, char *argv[]) 
{ 
    char buff; //command buffer 
    char* comand[comlen]; 
    int i; 
    do 
    { 
     i = 0; 
    printf("simsh: "); 

     char* whtspc = strtok (fgets(&buff, comlen, stdin)," "); //get input and tokenize 
     printf("[%lu] :: %s------------\nEND OF BUFF TEST\n", strlen(&buff), &buff); 

    while (whtspc != NULL) 
    { 
      comand[i]=(char*)malloc((sizeof(char)*strlen(whtspc))); //alloctie mem for commands 
      strncpy(comand[i], whtspc, strlen(whtspc)-1);      //coppy comand token to array index i 
      whtspc = strtok (NULL, " ");              //grab next token 
      i++;                          //incriment 
      /*trying to change new line character to NULL so that commands can be passed properly*/ 
//   if (comand[strlen(comand[i]) - 1] == "\n") 
//   { 
//    comand[strlen(comand[i]) - 1] = '\0'; 
//   } 
      //breka out incase index oversteps 
      if (i == 4096) 
       break; 
    } 
     //last entry in command should be null 
     comand[i] = NULL; 
     //fork to run in background 
     pid_t pid = fork(); 

     if (pid == 0) 
     { 
      //testing and pass comands to execvp 
      printf("START OF COMAND TEST\n!!!!!!!!!%s!!!!!!!!!!!!!!!!\n %lu\nEND OF COMAND TEST\n\n",comand[1], strlen(comand[0])); 
      execvp(comand[0], &comand); 
     } 

     else 
     { 
      //parent wait on child. 
      waitpid(pid, &i, WUNTRACED | WCONTINUED); 
     } 
    } 
    while(1); 

    return 0; 
} 

任何幫助將受到歡迎。

如果有幫助可言,這裏是代碼的終端輸出::

所有的
simsh: ls 
[3] :: ls 
------------ 
END OF BUFF TEST 
START OF COMAND TEST 
!!!!!!!!!(null)!!!!!!!!!!!!!!!! 
2 
END OF COMAND TEST 

chop_line.c chop_line.h list.c list.h Makefile Makefile~ One simsh1 simsh1.c simsh1.c~ 
simsh: ls -all 
[2] :: ls------------ 
END OF BUFF TEST 
START OF COMAND TEST 
!!!!!!!!!-all!!!!!!!!!!!!!!!! 
1 
END OF COMAND TEST 

simsh: echo 
[5] :: echo 
------------ 
END OF BUFF TEST 
START OF COMAND TEST 
!!!!!!!!!(null)!!!!!!!!!!!!!!!! 
4 
END OF COMAND TEST 


simsh: echo all 
[4] :: echo------------ 
END OF BUFF TEST 
START OF COMAND TEST 
!!!!!!!!!all!!!!!!!!!!!!!!!! 
3 
END OF COMAND TEST 

simsh: echo echo 
[4] :: echo------------ 
END OF BUFF TEST 
START OF COMAND TEST 
!!!!!!!!!echo!!!!!!!!!!!!!!!! 
3 
END OF COMAND TEST 
+0

你能更準確地描述出乎意料的行爲嗎? – hivert

+0

當我執行諸如'ls'這樣的命令時,它可以工作,但是當我嘗試執行像'ls -all -S'這樣的命令時,它不執行命令。或者如果我做'回聲測試',它不會迴應「測試」。我不確定爲什麼 –

+0

可能想查看[dash]的源代碼(http://git.kernel.org/cgit/utils/dash/dash.git/tree/src),它是一個小的posix shell沒有額外的。 – TechZilla

回答

0

首先,你fgets正在讀一個單一字符buff。你應該讀入一個字符緩衝區。其次,fgets保持在讀字符串的結尾換行,所以你可能需要先刪除它,例如:

char buff[4096]; 
if (!fgets(buff, sizeof(buff), stdin)) { 
    // error or EOF 
    return 1; 
} 
int len = strlen(buff); 
if (len > 0 && buff[len-1] == '\n') { 
    buff[--len] = '\0'; 
} 
char *whtspc = strtok(buff, " "); 

還必須與buff替換所有引用&buff

除此之外,您malloc也是錯誤的,並分配一個字符小於所需(strlen是沒有終止NUL):

if (!(comand[i] = malloc(strlen(whtspc)+1))) { 
    return 1; // out of memory 
} 
(void) strcpy(comand[i], whtspc); 

相應的strncpy被複制比需要一個字符少。這是您的原始代碼意外地爲單字輸入工作的原因,因爲它在這種情況下會爲您刪除尾隨'\n',但在所有其他情況下,它將刪除該單詞本身的最後一個字符。

,第二個參數,以execvp應該只是comand(原文如此)陣列:

execvp(comand[0], comand); 
+0

實施您的建議會產生段錯誤。即使我在提示使用'!fgets' if語句之後只拿到了部分內容,那麼'ls'命令就不再起作用了。我開始認爲我錯了這是我遇到的問題的原因。 我查閱了fgets的手冊頁,它的語法是'char * fgets(char * s,int size,FILE * stream);'給出'char buff [comlen]'爲char * s'?它也存儲在'\ n'以及追加'\ 0'。我不確定現在的問題是什麼。 –

+1

在這種情況下,「buff」衰減到指向其第一個元素的指針,即「&(buff [0])」。 C字符串以NUL結尾,但是'strlen'不計算終止符,所以'buff [strlen(buff)-1]'是當'buff'不包含空字符串時的最後一個字符(它會有'strlen'零)。 – Arkku

+1

@ user3078156我編輯了答案,以顯示爲使它適用於'ls'和'ls -l'輸入所需的全部更改。除了這些變化,你仍然在泄漏內存,因爲你沒有釋放'malloc''結果等。 – Arkku

1

的第一個參數fgets應的指針,其中的字符串被複制到緩衝區中。您正在傳遞一個指向單個的指針char

其次,execvp需要兩個參數:一個文件名和一個空終止的命令行參數列表,按照慣例,它們以文件名本身開頭。

我冒昧地對您的代碼進行了一些修改,既解決了上面提到的問題,又使其更具可讀性。

請注意,下面的代碼中存在內存泄漏(修復它:)。可能還有其他問題,我沒有注意到。

前段時間我實現了一個shell;如果你想看看,我的GitHub網址在我的個人資料中(注意:醜陋的大學作業代碼)。

希望它有幫助!

#include <stdio.h>                      
#include <stdlib.h>                      
#include <string.h>                      
#include <unistd.h>                      
#include <time.h> 
#include <sys/types.h>                     
#include <sys/wait.h>                     

#define COMLEN 4096                      
#define COMARG_N 32                      
#define TRUE 1 

int main(int argc, char *argv[]) 
{                          
    char *token;                       
    char *args[COMARG_N];                    
    char *buff;                       
    int i;                        
    pid_t pid;                       

    while(TRUE) {                      
     printf("simsh: ");                    

     buff = (char*) malloc(sizeof(char) * COMLEN);             
     fgets(buff, COMLEN, stdin);                 

     if (buff[strlen(buff) - 1] == '\n')               
      buff[strlen(buff) - 1] = '\0';                

     i = 0;                       
     token = strtok (buff, " ");                 

     while (token != NULL && i < COMARG_N - 1) {             
      args[i] = token;                   
      token = strtok (NULL, " ");                
      i++;                      
     }                        

     args[i] = NULL;                    

     pid = fork();                     
     if (pid == 0)                     
      execvp(args[0], &args[0]);                 
     else                       
      waitpid(pid, &i, WUNTRACED | WCONTINUED);             

     free(buff);                     
    }                         

    return 0;                        
} 
+1

爲什麼'malloc'和'free'是循環每次迭代的新'buff'?另外,你在連續兩次調用'strlen(buff)',並且在'strlen(buff)'之前不檢查'fgets'的返回值,或者檢查'buff [strlen(buff) - 1]之前的長度。 '。作爲樣式提示,'sizeof(char)'總是1(即'1 *'是一個NOP),'&args [0]'與'args'相同,不應該使用'malloc' ,並且定義你自己的'TRUE'非常難看(特別是因爲C約定是非零值是「真」的 - 至少你應該使用'stdbool.h'作爲標準值)。 – Arkku

+0

感謝您的評論 –