简体   繁体   English

在自定义外壳中处理参数

[英]Handling arguments in a custom shell

I am currently working on a shell, implemented in C, for class that I hope to build upon over time and have run into a problem with executing my arguments. 目前,我正在为用C实现的Shell编写类,我希望该类可以随着时间的推移逐步构建,并且在执行参数时遇到问题。 My program uses getchar() to parse entries into the array of arguments and then executes the arguments using execvp() . 我的程序使用getchar()将条目解析为参数数组,然后使用execvp()执行参数。 The issue I have is in repeated entry of arguments any subsequent shorter arguments are concatenated with characters left in memory somewhere. 我遇到的问题是重复输入参数时,任何后续的较短参数都与内存中剩余的字符连接在一起。 Example below. 下面的例子。 And I am required to use getchar , which rules out alternate methods of getting the arguments. 而且我需要使用getchar ,它排除了获取参数的替代方法。

//Global Variables    
char argument[64];  
char **argv;

int main(int argc, char** argv) {
    mainloop();                      //Loop that calls the commands
    return (EXIT_SUCCESS);
}

void prompt(){                       //Modular prompt
    printf ("?:");
}

void mainloop(){                    //Loop that calls the functions
    while(1){
        prompt();
        argv = (char**)malloc(sizeof(char*)*64);  //allocate memory for argv
        getcommand(argument, argv);
        if((strcmp(argv[0],"exit" )) == 0){  //check for exit
            return 0;
        }
        executecommand();
        printcommand();
        //clearcommand();
        //printcommand();
    }
}

void getcommand(char* argument, char** argv){  //Parser for the command
    int i=0,j=0;
    char c;
    char* token;
    while((c = getchar()) != '\n' ){ //gets char and checks for end of line
        argument[i] = c;
        i++;
    }
    token = strtok(argument, " ,.");  //tokenize the command
    while (token != NULL){ 
        argv[j] = token;   //pass command to array of arguments
        token = strtok(NULL, " ,.");
        j++;
    }
    //argv[j] = "\0";
}

void executecommand(){  //Function to call fork and execute with errors
    pid_t childpid = fork();
    int returnStatus;
    if(childpid == -1){                           //Fail to Fork
        printf("failed to fork");
        exit(1);
    }
    else if(childpid == 0){                      //Child process
        if (execvp(*argv, argv) < 0){
            printf("error executing\n");
            exit(1);
        }
        else{                                   //Execute successful
            printf("executed");
        }
    }
    int c=(int)waitpid(childpid, &returnStatus, 0);
    if (returnStatus == 0)  // Verify child process terminated without error.  
        {
            printf("The child process terminated normally. \n");   
        }

    if (returnStatus == 1)      
        {
            printf("The child process terminated with an error!.\n");    
        }
    //realloc(argv,64);
}

void printcommand(){  //Test function to print arguments
    int i = 0;
    while(argv[i] != NULL){
        printf("Argv%d: %s \n",i, argv[i] );
        i++;
    }
}

/*void clearcommand(){     //Function to clear up the memory, does not work
  int i=0;
  argv[0] = "       \0";
  argv[1] = "       \0";

  }*/

Example output: 输出示例:

?: ls -l
//functions as intended

?:echo
//argument returns as echol

This is the case for any entry which is shorter than a previous entry. 对于任何比上一个条目短的条目都是如此。 I do not understand why exec is reading the argument continuing after a '\\0' and i am sure that I am making a memory error here. 我不明白为什么exec在'\\0'之后继续读取参数,并且我确定自己在这里出错。 Help would be very much appreciated, I have been stuck on this one for a couple of days now. 非常感谢您的帮助,我已经坚持了几天。

You need to indicate the end of the argv array with an element that contains a null pointer. 您需要使用包含空指针的元素来指示argv数组的末尾。 The commented-out line: 注释掉的行:

argv[j] = "\0";

should be: 应该:

argv[j] = NULL;

You also need to put a null terminator at the end of the argument string. 您还需要在argument字符串的末尾放置一个空终止符。 You're getting l when you do the echo because argument still contains the previous command line. 执行echo时会得到l ,因为argument仍然包含前一个命令行。 So the first line sets argument to: 因此,第一行将argument设置为:

ls -l

Then you overwrite the first 4 characters with echo , so it becomes: 然后,您用echo覆盖前四个字符,因此它变为:

echol

So the full function would be: 因此完整的功能将是:

void getcommand(char* argument, char** argv){  //Parser for the command
    int i=0,j=0;
    char c;
    char* token;
    while((c = getchar()) != '\n' ){ //gets char and checks for end of line
        argument[i] = c;
        i++;
    }
    argument[i] = '\0';
    token = strtok(argument, " ,.");  //tokenize the command
    while (token != NULL){ 
        argv[j] = token;   //pass command to array of arguments
        token = strtok(NULL, " ,.");
        j++;
    }
    argv[j] = NULL;
}

You could also use fgets() to read a line of input, instead of calling getchar() yourself. 您也可以使用fgets()读取一行输入,而不用自己调用getchar()

You should also check for the input being larger than the size of argument . 您还应该检查输入是否大于argument的大小。

After the loop that reads an input line, you need to terminate the line with a NUL character. 在读取输入行的循环之后,您需要使用NUL字符终止该行。

while((c = getchar()) != '\n' ){ //gets char and checks for end of line
    argument[i] = c;
    i++;
}
argument[i] = '\0';  // <<---- terminate the input line

You also need to do what @Barmar said, but that's a different issue than the one that you describe in the question. 您还需要执行@Barmar所说的,但这与您在问题中描述的问题不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM