实现自己的shell

时间:2017-04-22 08:29:52

标签: c linux shell pipe

您好,感谢您的关注。我正在尝试实现自己的shell。我有一些关于我的代码和任务ro resolv的问题。下面我将介绍我之前的代码和问题:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>

void parse(char *line, char **argv, char **argv2)
{
    while (*line != '\0')
    {
        while (*line == ' ' || *line == '\t' || *line == '\n')
        {
            *line++ = '\0';
        }   

        if(*line == '>' && *(line+1) == '>')
        {
            while (*line != '\0' && *line != ' ' &&  *line != '\t' && *line != '\n')
            {
                line++;
            }           
            while (*line == ' ' || *line == '\t' || *line == '\n')
            {           
                *line++ = '\0';
            }
            *argv2 = line;
            break;
        }

        if(*line == '&')
        {
            break;
        }

        *argv++ = line;

        while (*line != '\0' && *line != ' ' &&  *line != '\t' && *line != '\n')
        {
            line++;
        }   
    }
    *argv = '\0';
}

void execute(char **argv, int option)
{
    pid_t pid;
    int status;

    if ((pid = fork()) < 0)
    {
        printf("*** ERROR ***\n");
        exit(1);
    }
    else if (pid == 0)
    {
        if (execvp(*argv, argv) < 0)
        {
            printf("*** ERROR ***\n");
            exit(1);
        }
    }
    else if(option == 1)
    {
        while (wait(&status) != pid);
    }
}

void execute2(char *command, char **argv, char **argv2)
{
    pid_t pid;
    int status;

    if ((pid = fork()) < 0)
    {
        printf("*** ERROR ***\n");
        exit(1);
    }
    else if (pid == 0)
    {
        //close(1);
        parse(command, argv, argv2);
        int output = open(*argv2, O_APPEND | O_WRONLY);
        dup2(output,1);
        if (strcmp(argv[0], "exit") == 0)
            exit(0);
        if (execvp(*argv, argv) < 0)
        {
            printf("*** ERROR ***\n");
            exit(1);
        }
        close(output);
    }
    else
    {
        while (wait(&status) != pid);
    }
}

int specialChar(char *argv)
{
    int i=0;
    while(argv[i]!='\0')
    {
        if(argv[i]=='>' && argv[i+1]=='>')
            return 1;           
        else if(argv[i]=='&')
            return 2;           
        else if(argv[i]=='|')
            return 3;           
        i++;
    }
}

void  main()
{
    char command[20];
    char *argv[64];
    char *argv2[1];
    char **history = (char**)malloc(20*sizeof(char*));
    int counterHistory1=-1;
    int counterHistory2=0;
    int i;

    for(counterHistory2 = 0; counterHistory2<20; counterHistory2++)
    {
        history[counterHistory2]=(char*)malloc(100*sizeof(char));
    }

    FILE *file;
    file=fopen("history", "w");
    if(!file)
        printf("ERROR");

    while (1)
    {
        printf("Shell -> ");
        gets(command);

        counterHistory1++;
        strcpy(history[counterHistory1],command);
        fopen("history", "w");
        if(counterHistory1<20)
            for(i=0; i<=counterHistory1; i++)
            {
                fprintf(file,"%s\n",history[i]);
            }
        else
            for(i=counterHistory1-20; i<counterHistory1; i++)
            {
                fprintf(file,"%s\n",history[i]);
            }

        fflush(file);
        printf("\n");

        switch(specialChar(command))
        {
            case 1:
                //close(1);
                execute2(command,argv,argv2);
            break;

            case 2:                                //running program in background
                parse(command, argv, argv2);
                if (strcmp(argv[0], "exit") == 0)
                    exit(0);
                execute(argv,0);
            break;

            case 3:

            break;

            default:
                parse(command, argv, argv2);
                if (strcmp(argv[0], "exit") == 0)
                    exit(0);
                execute(argv,1);
            break;
        }
        fclose(file);
        }
}

1)来自用户的最后一个标志是&#39;&amp;&#39;我需要在后台运行我的程序。我已经读过,如果我不打电话等,我可以这样做。我做得好还是应该换一些东西?

2)如果我发现&#34;&gt;&gt;&#34;我应该将输出重定向到文件。例如,我得到ls&gt;&gt;输出,所有目录和文件应写入文件&#34;输出&#34;。不幸的是,它只运行一次。在此之后我的程序停止了。我认为过程从未完成,然后我无法写下一个命令。我试图杀死那个过程,但它没有用,或者我做错了什么。

3)在我的shell中,我应该使用|创建任意长度的管道标志。我不知道如何解决这个问题...

感谢您的回答和帮助。

1 个答案:

答案 0 :(得分:0)

回答1

在shell中,创建的进程是shell的子进程,需要通过访问stdout,stdin和stderr来控制终端

    signal(SIGTTOU, SIG_IGN);

    setpgid(getpid(),getpid());

    if(background==false) //shell for foreground process
    {
        tcsetpgrp(0,getpgid(getpid())); //access to stdin
        tcsetpgrp(1,getpgid(getpid())); //access to stdout
        tcsetpgrp(2,getpgid(getpid())); //access to stderr
    }
    execvp(command,args);