2013-11-21 45 views
0

我寫了這個簡單的殼到目前爲止。但是我的外殼遇到了一些麻煩。 例如,當我嘗試通過命令「evince pdffile.pdf」打開pdf文件時,實際的pdfile不會打開。 PDF查看器運行,但整個內容的實際文件從不出現。 或者另一個例子是命令「ls -l」。我沒有列出應該列出的文件和文件夾,但「ls」正在工作。 另一個例子是gedit,等等。 另外,我應該提到。我不使用「system()」,因爲system()會做所有事情,我不會有事情要做。相反,我使用「execvp()」。 這是代碼。我希望你可能會發現問題,因爲我不知道問題是由什麼引起的。C - 在linux上的一個簡單的shell - 命令的一些麻煩

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

#define MAX_LENGTH 1024 
#define DELIMS " \t\r\n" 

void exec_cmd (char *buf); 

int main() {  
    char line[MAX_LENGTH]; 
    char * cmd; 
    char curDir[100]; 

    while (1) { 
     getcwd(curDir, 100); 
     printf("%[email protected]%s$ ", getlogin(), curDir); 
     if (!fgets(line, MAX_LENGTH, stdin)) 
      break; 

     if ((cmd = strtok(line, DELIMS))) { 
      errno = 0; 
      if (strcmp(cmd, "cd") == 0) { 
       char *arg = strtok(0, DELIMS); 

       if (!arg) 
       fprintf(stderr, "cd: argument is missing.\n"); 
       else chdir(arg); 

      } else if (strcmp(cmd, "exit") == 0) { 
       exit(0); 

      } else exec_cmd(line); 

     if (errno) perror("Error. Command failure"); 
     } 
    } 
return 0; 
} 

void exec_cmd (char *buf) { 
    int status = 0; 
    char *argv[MAX_LENGTH]; 
    int j=0; 
    pid_t pid; 
    argv[j++] = strtok (buf, DELIMS); 
    while (j<MAX_LENGTH && (argv[j++]=strtok(NULL,DELIMS))!=NULL); // EDIT: " " replaced by DELIMS 

    pid = fork(); 
    if(pid < 0) { 
     printf("Error occured"); 
     exit(-1); 
    } else if(pid == 0) { 
     execvp(argv[0],argv); 
    } else if(pid > 0) { 
     wait(&status); 
    } 
} 

回答

1

檢查的參數(例如,打印出來,每個封閉在[])你叫fork/exec之前,有一個很好的機會,他們你在想什麼。

當您第一次撥打strtok時會使用您的完整分隔符集,而後續的呼叫則不會。他們只是使用一個空間。這意味着最後的參數可能會在fgets的字符串中留下換行符。我會在隨後的調用中使用相同的分隔符。換句話說:

while (j<MAX_LENGTH && (argv[j++]=strtok(NULL,DELIMS))!=NULL); 

已經輸入驗證碼,並做到這一點的調試,我發現,傳遞給函數的字符串永遠只能有這一個字。事實證明,這是因爲main發生的strtok檢查cd/exit。在第一個單詞的結尾處留下了nul字符,這是strtok工作方式固有的一種效果。

大概最快的解決方法是使字符串的副本前主初始strtok,然後傳遞的功能。換句話說,使用strdup(和更高版本,free)。現在,glibc 擁有 a strdup但是,如果您所在的環境不是(它是POSIX而不是ISO),請參閱here

+0

是的,你是對的。我錯過了最後一個strtok。我糾正了這個錯誤,但問題依然存在。 – tumbler

+0

@ user2965601:並且,當您打印出參數時,您看到了什麼?修復之前和之後。這是答案的關鍵,也是調試實際問題的最佳解決方案。 – paxdiablo

+0

我用while循環在另一個數組中複製了行[]的內容。 它似乎在工作。我還應該使用strdup嗎? – tumbler

1

該錯誤在main()

您正在使用strtok來查找該行的第一個單詞。但strtok修改該行,使其實際上包含該單詞(NUL終止符被寫入緊跟其後的字符串)。

您需要複製該行,或使用strtok_s或執行其他操作以避免修改行。

+0

爲了清楚「line」是否包含「hello world」,當你創建strtok行時,它將變成「hello \ 0world」,所以當你將行傳遞給exec_cmd時,它會被解釋爲只包含「hello」的字符串。 – Duck

+0

你說得對。這是造成這個問題的原因。如果沒有你,我不會看到那些人。 謝謝! :) – tumbler

+0

@Duck:就在之前,我試圖將其打印出來,但沒有奏效。你可能會告訴我如何正確打印它? – tumbler