2014-02-14 70 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'中。 –