我从事这个项目已有一段时间了。目的是使功能正常的shell可以执行几乎所有的shell命令(cd除外)。它完成了我想要做的几乎所有事情,除了几件事。首先是,当我放置一个“&”来表示后台处理时,它会执行此操作,但是不会打印另一行myshell>行。我仍然可以输入内容,但是无论我在哪里放置另一个cout <”;,myshell>都不会显示。

另一个问题是,如果我按Enter键,多次使myString为空,它会因段错误而使程序崩溃。同样,在我执行'&'后台处理并按Enter以使myshell>重新启动后,它会打印一个myshell>,但是在回车的下一个匹配项上出现段错误。如果我不能很好地解释这一点,我感到抱歉,但这确实使我发疯。如果您有任何建议,请告诉我。

#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <cstdio>
#include <sys/wait.h>
#include <stdio.h>

/*Function that parses the command the user inputs.
  It takes myArgv and myString as inputs.
  It returns the value of exitcond, which is used to see if the user wants to exit or not.
  Also, this is where myString is tokenized using strok()*/
int parseCommand(char *myArgv[10], char myString[255])
{
    int exitcond=0;
    if((strcmp(myArgv[0], "exit") == 0)||(strcmp(myArgv[0], "quit")==0))
    {
        exitcond = 1;
        return exitcond;
    }
    int i;
    char *token;
    token = strtok(myString," ");
        i=0;
        while (token != NULL)
        {
            myArgv[i] = token;
            token = strtok(NULL," ");
            i++;
        }

        /*
         * Set the last entry our new argv to a null char
         * (see man execvp to understand why).
         */
        myArgv[i] = '\0';
    return exitcond;
}
/*Function that gets the command from the user and sees if they want
background processing or not (presence of '&').
  It takes inputs of choose and myString. choose is the variable for
whether background processing is necessary or not, while myString is
an empty character array.
  It outputs the value of the choose variable for lter use.*/
int getCommand(int choose, char myString[255])
{
    int i;
    choose=0;
    fgets(myString, 256, stdin);
    if (myString[0]=='\0')
    {
        choose=0;
        return choose;
    }
        for (i=0; myString[i]; i++)
        {
            if (myString[i]== '&')
            {
            choose=1;
            myString[i]=' ';
        }

        if (myString[i] == '\n')
        {
            myString[i] = '\0';
        }
    }
    return choose;
}
/*Main function where all the calling of other functions and processes
is done. This is where the user enters and exits the shell also. All
usage of fork, pid, waitpid and execvp is done here.*/
int main()
{
    using namespace std;
    int exitCondition=0, i=0, status;
    char myString[255];
    char *token, *myArgv[10];
    pid_t pid, waiting;
    int bg=0;
    while (!exitCondition)
    {
        /* print a prompt and allow the user to enter a stream of characters */
        cout << "myshell> ";
        bg=0;
        int choose=0;
        bg=getCommand(choose,myString);
        exitCondition=parseCommand(myArgv,myString);
        if(exitCondition==1)
        {
            cout<<"Thank you for using my shell.\n";
        }

    else {
     /*   while (myString[0]=='\0')
        {
            cout<<"myshell> ";
            bg=getCommand(choose,myString);
        }*/
        /* The user has a command, so spawn it in a child process */

        pid = fork();

        if (pid == -1)
        {
            /* to understand why this is here, see man 2 fork */
            cout << "A problem arose, the shell failed to spawn a child process" << endl;
            return(1);
        }

        else if (pid == 0)
        {
            // Child process
            execvp(myArgv[0],myArgv);
            cout << "Bad command or file name, please try again!\n" << endl;
            return 0;
        } else {
            /* This makes sure that the spawned process is run in the foreground,
               because the user did not choose background */
            if(bg==0)
            {
                waitpid(pid,NULL,0);

            }
          }

    }
}
return 0;
}

最佳答案

好的,您有三个错误,其中一个引起了段错误。在其他程序中,一个将在传递给execvp的数组中放入垃圾参数,另一个将泄漏用于后台作业的僵尸进程。

我已经更正了代码,并在其中指出了错误的位置以及修复程序(请原谅免费的样式清理):

#include <cstdio>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define AVCOUNT     100
#define STRBUFLEN   2000

/*Function that parses the command the user inputs.
  It takes myArgv and myString as inputs.
  It returns the value of exitcond, which is used to see if the user wants to
  exit or not.
  Also, this is where myString is tokenized using strok()*/
int
parseCommand(char **myArgv, char *myString)
{
    char *token;
    char *bp;
    int exitcond = 0;
    int i;

    // NOTE/BUG: original check for exit/quit was here -- at this point
    // myArgv is undefined (hence the segfault)

    // NOTE/BUG: your original loop -- at the end i was one beyond where it
    // should have been so that when myArgv gets passed to execvp it would
    // have an undefined value at the end
#if 0
    token = strtok(myString, " ");
    i = 0;
    while (token != NULL) {
        myArgv[i] = token;
        token = strtok(NULL, " ");
        i++;
    }
#endif

    // NOTE/BUGFIX: here is the corrected loop
    i = 0;
    bp = myString;
    while (1) {
        token = strtok(bp, " ");
        bp = NULL;

        if (token == NULL)
            break;

        myArgv[i++] = token;
    }

    /*
     * Set the last entry our new argv to a null pointer
     * (see man execvp to understand why).
     */
    // NOTE/BUG: with your code, i was one too high here
    myArgv[i] = NULL;

    // NOTE/BUGFIX: moved exit/quit check to here now that myArgv is valid
    token = myArgv[0];
    if (token != NULL) {
        if ((strcmp(token, "exit") == 0) || (strcmp(token, "quit") == 0))
            exitcond = 1;
    }

    return exitcond;
}

/*Function that gets the command from the user and sees if they want
  background processing or not (presence of '&').
  It takes inputs of choose and myString. choose is the variable for
  whether background processing is necessary or not, while myString is
  an empty character array.
  It outputs the value of the choose variable for lter use.*/
int
getCommand(int choose, char *myString)
{
    int i;

    choose = 0;
    fgets(myString, STRBUFLEN, stdin);

    if (myString[0] == '\0') {
        choose = 0;
        return choose;
    }

    for (i = 0; myString[i]; i++) {
        if (myString[i] == '&') {
            choose = 1;
            myString[i] = ' ';
        }

        if (myString[i] == '\n') {
            myString[i] = '\0';
            break;
        }
    }

    return choose;
}

/*Main function where all the calling of other functions and processes
  is done. This is where the user enters and exits the shell also. All
  usage of fork, pid, waitpid and execvp is done here.*/
int
main()
{
    using namespace std;
    int exitCondition = 0;
    int status;
    char myString[STRBUFLEN];
    char *myArgv[AVCOUNT];
    pid_t pid;
    int bg = 0;

    while (!exitCondition) {
        // NOTE/BUGFIX: without this, any background process that completed
        // would become a zombie because it was never waited for [again]
        // reap any finished background jobs
        while (1) {
            pid = waitpid(0,&status,WNOHANG);
            if (pid < 0)
                break;
        }

        /* print a prompt and allow the user to enter a stream of characters */
        cout << "myshell> ";
        bg = 0;
        int choose = 0;

        bg = getCommand(choose, myString);

        exitCondition = parseCommand(myArgv, myString);
        if (exitCondition == 1) {
            cout << "Thank you for using my shell.\n";
            break;
        }

        /* while (myString[0]=='\0') { cout<<"myshell> "; bg=getCommand(choose,myString); } */
        /* The user has a command, so spawn it in a child process */

        pid = fork();

        if (pid == -1) {
            /* to understand why this is here, see man 2 fork */
            cout << "A problem arose, the shell failed to spawn a child process" << endl;
            return 1;
        }

        if (pid == 0) {
            // Child process
            execvp(myArgv[0], myArgv);
            cout << "Bad command or file name, please try again!\n" << endl;
            return 1;
        }

        /* This makes sure that the spawned process is run in the
        foreground, because the user did not choose background */
        if (bg == 0)
            waitpid(pid, &status, 0);
    }

    return 0;
}

关于c++ - Myshell Segmentation Fault,获取输入可能存在问题?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35354358/

10-13 07:43