我试图创建一个简单的shell程序,并使用fgets()从用户那里获取输入。我将用户输入存储在char []中,然后尝试使用我编写的getword()方法进行解析。但是,我不知道如何获取getword()方法来解析字符串。我可以打印出commandLine char []并确切地看到在提示符下键入的内容,但是没有得到解析。 getword()返回未解析的相同字符串,并尝试将整个内容存储在argv [0]中。我已经单独测试了getword()方法,它返回了我想要的结果。这是我目前的尝试:

主要的shell程序:

int main() {
    pid_t pid, first, second;
    mode_t fileBits;
    size_t ln;
    int argc, inputRedirect, firstStatus, i, execvpReturnVal;
    int childOutput_fd;
    long octalPermissionString;
    char *home = getenv("HOME");
    char *argv[MAXITEM];
    char devNull[10] = "/dev/null";
    char commandLine[STORAGE];
    struct stat fileStats;

    signal(SIGTERM, myhandler);

    for (;;) {
        background = 0;
        printf("p2: ");
        fflush(stdout);


        /*---------FGETS PROMPT----------*/

        fgets(commandLine, STORAGE, stdin);
        commandLine[strlen(commandLine) - 1] = '\0';
        printf("commandLine = [%s]\n", commandLine);
/*==============OTHER SHELL METHODS=============*/


调用getword()的parse()方法:

int parse(char *commandLine, char *argv[]) {
    int argc = 0;
     char *commandPointer;
     argv[argc++] = commandLine;
     printf("argv[%d] = [%s]\n", argc-1, commandLine);

     do{
     commandPointer = (char*)malloc(sizeof(char) * STORAGE);
     argv[argc++] = commandPointer;
     printf("argv[%d] = [%s]\n", argc-1, commandPointer);
     getword(commandPointer);
     }while(*commandPointer != '\0');
     argc--;
     argv[argc] = '\0';
     return argc;

}


getword()解析方法:

/*Function Prototypes*/
int tilde(char *p, int i);
int isMeta(int thisChar);


int getword(char *w) {

int currChar, nextChar, offset;
int index = 0;
int *tildeHelper;

currChar = getchar();

while(currChar == ' ' || currChar == '\t') {
    currChar = getchar();
}

if(currChar == EOF)
    return -1;


switch(currChar) {
    case '\0':
        w[index] = '\0';
        return index;
    case '\n':
        w[index] = '\0';
        return index;
    case ';':
        w[index] = '\0';
        return index;
    case '<':
        w[index++] = currChar;
        w[index] = '\0';
        return index;
    case '>':
        w[index++] = currChar;
        if((nextChar = getchar()) == '>')
            w[index++] = currChar;
        else {
            ungetc(nextChar, stdin);
        }
        w[index] = '\0';
        return index;
    case '|':
        w[index++] = currChar;
        w[index] = '\0';
        return index;
    case '&':
        w[index++] = currChar;
        w[index] = '\0';
        return index;
    case '~':
        tildeHelper = &index;
        index = tilde(&w[index], *tildeHelper);

    default:
        w[index++] = currChar;
        while((currChar = getchar()) != ' ' && currChar != '<' && currChar != '>' && currChar != '|' && currChar != ';' && currChar != '&' && currChar != '\t' && currChar != '\n' && currChar != '\0' && currChar != EOF && index <= STORAGE - 1) {
            switch(currChar) {
                case '~':
                    tildeHelper = &index;
                    index = tilde(&w[index], *tildeHelper);
                    break;

                case '\\':
                    nextChar = getchar();
                    if(metaCharacter(nextChar))
                        w[index++] = nextChar;
                    else {
                        ungetc(nextChar, stdin);
                        w[index++] = currChar;
                    }
                    break;

                default:
                    w[index++] = currChar;
            }
        }
        ungetc(currChar, stdin);
        w[index] = '\0';
        return index;
}
}


int tilde(char *cp, int i) {
    int *ip = &i;
    char *p = cp;
    char *o;
    o = (strcpy(p, getenv("HOME")));
    int offset = strlen(o);
    *ip = *ip + offset;
    return i;
}

int metaCharacter(int thisChar) {
    int isMeta = 0;
    switch(thisChar) {
        case '~':
            isMeta = 1;
            break;
        case '<':
            isMeta = 1;
            break;
        case '>':
            isMeta = 1;
            break;
        case '|':
            isMeta = 1;
            break;
        case ';':
            isMeta = 1;
            break;
        case '&':
            isMeta = 1;
            break;
        case '\\':
            isMeta = 1;
            break;
    }
    return isMeta;
}

最佳答案

您试图从stdin读取命令行两次。首先,用fgets()读整行,然后在getword中尝试用getchar()获取下一个字符。实际上,这试图读取第二行。您应该改为读取包含该行的char缓冲区。

更新您的getword函数以使用第二个参数src,即要读取的行。然后将所有对getline的调用替换为*src++

int getword(char *w, const char *src) {

    int currChar, nextChar, offset;
    int index = 0;
    int *tildeHelper;

    currChar = *src++;
    while(currChar == ' ' || currChar == '\t') currChar = *src++;

    /* ... */
}


然后,您的parse函数必须将命令行传递给getword并使用getword的返回值来更新字符串位置:

int parse(char *commandLine, char *argv[])
{
    int argc = 0;
    int index = 0;

    while (1) {
        char *commandPointer = malloc(sizeof(char) * STORAGE);
        index += getword(commandPointer, commandLine + index);
        if (*commandPointer == '\0') break;
        argv[argc++] = commandPointer;
    }

    return argc;
}


这样,您仍然在代码中遇到问题,例如,未正确获得getword的返回值以及未释放参数字符串。

另外,要实现外壳程序,请查看getline,它是比普通的旧版“ fgets”更好的命令行输入界面。

09-16 19:39