2014-02-14 114 views
0

我正在一個項目中,我必須在C編寫一個Linux命令shell。到目前爲止,它的工作對於沒有輸入的命令(即,shell將運行'日期'命令和'ls'命令正常。)execvp和閱讀命令參數

但是,需要一些輸入的命令,它似乎像讀取每個輸入作爲一個單獨的命令。例如,對於下面的命令:

% gcc -o testFile testFile.c 

看起來好像殼運行gcc作爲自己的命令,然後-o,然後TESTFILE,當它應該採取gcc作爲指揮,與testfile.c其他三項作爲輸入。

我不明白代碼中發生了什麼 - 它可能來自完全不瞭解execvp函數(我從幾個來源閱讀了它,我仍然不認爲我理解它 - 我以爲我做了!)。

execvp調用在函數execute中。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include "commandStorage.c" 

#define MAX_ARGUMENTS 10 


void parseLine(char *command, char **args) { 

const char split = '\0'; 
int i; 
char *ptrToken; 

while(*command != '\0') { 
    while ((*command == '\n') || (*command == '\t') 
     || (*command == ' ')) { 
     *(command++) = '\0'; 
     } // end 'while' 
    *args++ = command; 
    printf("%s\n", command); 
    while ((*command != '\n') && (*command != '\t') 
     && (*command != '\0') && (*command != ' ')) { 
     command++; 
     } // end 'while' 

    } // end 'while' 
*args = '\0'; 
} // end parseLine 

void execute(char **arrayOfPtrs) { 
/* 
CURRENT BUG: 
The function is taking the array of pointers, and executing each 
input from the array seperately. 

The execvp function is being misused. 
*/ 
pid_t pid; 
int waitStatus; 

switch (pid = fork()) { 
    case 0: // Child process 
     if (execvp(arrayOfPtrs[0], arrayOfPtrs) < 0) { 
      perror("THE COMMAND FAILED TO EXECUTE!"); 
      break; 

      } // end 'if 

    case -1: // Fork failed 
     perror("THE PROCESS FAILED TO FORK"); 
     break; 

    default: // Parent process 
     while ((wait(&waitStatus) != pid)) {}; 
     break; 
} // end 'switch' 
return; 
} // end 'execute 

void clearPointerArray(char **args){ 

while (*args != NULL) { 
    *(args++) = NULL; 
} 
} 


int main() { 

int i; 
char command[MAX_STRING_LENGTH]; // unparsed command 
pid_t pid; 
char *args[MAX_ARGUMENTS]; // Argument vector. 


while(1) { 
    clearPointerArray(args); 
    printf("%s", "TimsShell--> "); 
    scanf("%s", command); 

    parseLine(command, args); 

    if ((strcmp(args[0], "exit") == 0) || (strcmp(args[0], "quit") == 0)) { 
     printf("%s\n", "Goodbye!"); 
     return 0; 
    } 

    execute(args); 

    }// while loop 
return 0; 

} // main 

這裏是從命令行一些輸出:

% gcc -o mainShell mainShell.c 
% ./mainShell 
TimsShell--> date 
date 
Fri Feb 14 15:50:28 EST 2014 
TimsShell--> ls 
ls 
change.log  doLocalConf.xml license.txt notepad++.exe session.xml    testFile.c 
commandStorage.c functionList.xml localization plugins  shortcuts.xml   themes 
config.model.xml langs.model.xml mainShell  readme.txt  stylers.model.xml updater 
config.xml  langs.xml  mainShell.c SciLexer.dll  stylers.xml   user.manual 
TimsShell--> gcc -o testFile testFile.c 
gcc 
gcc: fatal error: no input files 
compilation terminated. 
TimsShell--> -o 
THE COMMAND FAILED TO EXECUTE!: No such file or directory 
TimsShell--> testFile 
THE COMMAND FAILED TO EXECUTE!: No such file or directory 
TimsShell--> testFile.c 
: not found 2: testFile.c: 
testFile.c: 3: testFile.c: Syntax error: "(" unexpected 
TimsShell--> ^C 
+0

您是否能治療''一個原因,'\ N'和'\ t'特別,而不是像個一個真正的shell會允許'IFS'中的任何字符作爲分隔符(使用'\ n \ t'作爲默認的IFS值)?我認爲你在這裏做的方式實際上使得代碼難以遵循,而不是正確的行爲。 –

回答

1

參考手冊頁的scanf爲什麼發生這種情況。問題是在你的格式字符串:

%S

匹配的非空白字符的序列;下一個指針 必須是一個指向字符數組的指針,該指針的長度足以容納 輸入序列和自動添加 的終止空字節('\ 0')。輸入字符串停留在空白處或最大字段寬度處,以先發生者爲準。

試試這個:

scanf("%[^\n]s", command); 
getchar(); 

scanf(" %[^\n]s", command); 
+1

甚至更​​好,使用'fgets()'。 –

+0

scanf(「%[^ \ n] s」,a)不起作用 - 它只是一遍又一遍地重複命令。 對於fgets(),我沒有要從中提取的文件 - 我只是想提取用戶輸入。 – newalchemy

+1

@newalchemy:使用'fgets(command,MAX_STRING_LENGTH,stdin);'。這裏'scanf()'的用法是不安全的,因爲你沒有限制輸入長度,但是你試圖把它全部存儲在'command'中。 –