exit命令在我自己的shell中无法正常工作

时间:2013-04-25 04:14:24

标签: c linux shell exit

我为一个赋值编写了一个shell,它工作正常,但是有一个小的运行时错误,我无法弄清楚。当用户通过shell输入命令'exit'时,它应该来自新创建的shell。但问题是我必须多次输入命令'exit'才能退出shell。如果有人可以帮助我,那将是我的一大荣幸!谢谢大家!

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

char* cmndtkn[256];
char buffer[256];
char* path=NULL;
char pwd[128];

int main(){

//setting path variable 
    char *env;
    env=getenv("PATH"); 
    putenv(env);

    system("clear");

printf("\t MY OWN SHELL !!!!!!!!!!\n ");
printf("_______________________________________\n\n");

while(1){

    fflush(stdin);
    getcwd(pwd,128);
    printf("[MOSH~%s]$",pwd);

    fgets(buffer,sizeof(buffer),stdin);
    buffer[sizeof(buffer)-1] = '\0';

    //tokenize the input command line   
    char* tkn = strtok(buffer," \t\n");
    int i=0;
    int indictr=0;

        // loop for every part of the command
        while(tkn!=NULL)
        {
            if(strcoll(tkn,"exit")==0 ){
                exit(0);                
            }

            else if(strcoll(buffer,"cd")==0){

            path = buffer;
            chdir(path+=3);}

            else if(strcoll(tkn,"|")==0){

            indictr=i;}
            cmndtkn[i++] = tkn;
            tkn = strtok(NULL," \t\n");

        }cmndtkn[i]='\0';

// execute when command has pipe. when | command is found indictr is greater than 0.
    if(indictr>0){

    char* leftcmnd[indictr+1];
    char* rightcmnd[i-indictr];
    int a,b;

        for(b=0;b<indictr;b++)
        leftcmnd[b]=cmndtkn[b];

        leftcmnd[indictr]=NULL;

        for(a=0;a<i-indictr-1;a++)
        rightcmnd[a]=cmndtkn[a+indictr+1];

        rightcmnd[i-indictr]=NULL;

    if(!fork())
    {   
        fflush(stdout);
        int pfds[2];
        pipe(pfds);

            if(!fork()){

                close(1);
                dup(pfds[1]);
                close(pfds[0]);
                execvp(leftcmnd[0],leftcmnd);
                }   
            else{

                close(0);
                dup(pfds[0]);
                close(pfds[1]);
                execvp(rightcmnd[0],rightcmnd);
            }

    }else wait(NULL);

//command not include pipe 

        }else{

        if(!fork()){
            fflush(stdout);
            execvp(cmndtkn[0],cmndtkn);

        }else wait(NULL);

        }

}

}

1 个答案:

答案 0 :(得分:1)

cd命令一样,exit命令必须由shell解释为内置命令;它必须退出循环或直接调用exit()函数。但是,它似乎也应该发生。请注意,使用strcoll()有点不寻常;通常,strcmp()就足够了。

如果execvp()返回,您应该报告问题 - 并且您必须确保子shell退出,以便您没有多个shell进程同时读取输入。我想知道这个问题是否正在发生,这就是你必须多次输入exit的原因。

您还需要检查fgets()是否未报告错误。它始终为null终止其输入;您的代码不会消除换行符(您需要strlen(buffer)-1而不是sizeof(buffer)-1)。

读取和设置PATH的代码是错误的。 getenv("PATH")返回指向PATH=部分后面的第一个字符的指针;然后用它来“设置”环境。幸运的是,PATH的平均值不包含任何看起来像VAR=value的东西,因此它在功能上是一个无操作(虽然信息可能被复制到环境中,在那里它会造成混乱而不会导致任何重大问题伤害)。

你的代码缩进方案充其量只是洛可可 - 大多数情况下,它只是非常不一致。请保持一致!代码中的行间距也非常不稳定。当您在SO中添加代码时,不要使用制表符,每个缩进级别使用4个空格,突出显示左对齐的代码块并使用上方的 {} 按钮编辑框将其缩进为代码。这也意味着您不需要在代码中添加空行。

您没有关闭足够的文件描述符。当您使用dup()(或dup2())将管道复制到标准输入或标准输出时,您必须关闭由pipe()返回的文件描述符的两个

在Linux上,使用fflush(stdin)是未定义的行为,AFAIK。它在Windows上定义,但在POSIX系统上没有定义。

您不会检查您的chdir()系统调用是否有效。


尝试使用您的代码,我确实得到了一个失控的提示。不幸的是,我无法记住或看到是什么引发了失控。下面的代码大部分都是消毒的,似乎表现得很好。我注释了一些重要的变化 - 而不是其他变化。为了自己的利益,你应该做的一件事就是像dump_cmd()函数一样包含跟踪,这样你就可以看到你的程序正在做什么。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

char *cmndtkn[256];
char  buffer[256];
char *path = NULL;
char  pwd[128];

static void dump_cmd(char **argv);

int main(void)
{
    /*
    //setting path variable
    char *env;
    env=getenv("PATH");
    putenv(env);
    system("clear");
    */

    printf("\t MY OWN SHELL !!!!!!!!!!\n ");
    printf("_______________________________________\n\n");

    while (1)
    {
        //fflush(stdin);
        getcwd(pwd, 128);
        printf("[MOSH~%s]$", pwd);

        if (fgets(buffer, sizeof(buffer), stdin) == 0)
        {
            putchar('\n');
            break;
        }
        //buffer[sizeof(buffer)-1] = '\0';
        buffer[strlen(buffer)-1] = '\0';

        //tokenize the input command line
        char *tkn = strtok(buffer, " \t\n");
        int i = 0;
        int indictr = 0;

        // loop for every part of the command
        while (tkn != NULL)
        {
            if (strcoll(tkn, "exit") == 0)
            {
                printf("Got: exit\n");
                fflush(stdout);
                exit(0);
            }
            else if (strcoll(tkn, "cd") == 0)   // Was buffer, not tkn
            {
                printf("Got: cd (%s)\n", buffer + 3);
                fflush(stdout);
                path = buffer;
                chdir(path += 3);
            }
            else if (strcoll(tkn, "|") == 0)
            {
                indictr = i;
            }
            cmndtkn[i++] = tkn;
            tkn = strtok(NULL, " \t\n");
        }
        cmndtkn[i] = 0;

        // execute when command has pipe. when | command is found indictr is greater than 0.
        if (indictr > 0)
        {
            char *leftcmnd[indictr+1];
            char *rightcmnd[i-indictr];
            int a, b;

            for (b = 0; b < indictr; b++)
                leftcmnd[b] = cmndtkn[b];

            leftcmnd[indictr] = NULL;

            for (a = 0; a < i-indictr-1; a++)
                rightcmnd[a] = cmndtkn[a+indictr+1];

            rightcmnd[i-indictr-1] = NULL;  // Did not include -1

            if (!fork())
            {
                fflush(stdout);
                int pfds[2];
                pipe(pfds);

                if (!fork())
                {
                    dump_cmd(leftcmnd);
                    close(1);
                    dup(pfds[1]);
                    close(pfds[0]);
                    close(pfds[1]);
                    execvp(leftcmnd[0], leftcmnd);
                    fprintf(stderr, "failed to execvp() %s\n", leftcmnd[0]);
                    exit(1);
                }
                else
                {
                    dump_cmd(rightcmnd);
                    close(0);
                    dup(pfds[0]);
                    close(pfds[0]);
                    close(pfds[1]);
                    execvp(rightcmnd[0], rightcmnd);
                    fprintf(stderr, "failed to execvp() %s\n", rightcmnd[0]);
                    exit(1);
                }
            }
            else
                wait(NULL);

        }
        else
        {
            //command does not include pipe
            if (!fork())
            {
                dump_cmd(cmndtkn);
                fflush(stdout);
                execvp(cmndtkn[0], cmndtkn);
                fprintf(stderr, "failed to execvp() %s\n", cmndtkn[0]);
                exit(1);
            }
            else
                wait(NULL);
        }
    }

    return 0;
}

static void dump_cmd(char **argv)
{
    int i = 0;
    fprintf(stderr, "%d: Command:\n", (int)getpid());
    while (*argv != 0)
        fprintf(stderr, "%d: %d: [[%s]]\n", (int)getpid(), i++, *argv++);
}

我并不热衷于代码,但看起来确实很健全。