minishell

shell就是一个命令解释器
--------------------------------------------------------------------------更新中-----------------------------------------------------------------

实现思路:
1、等待用户的标准输入 [ls -l -a];
2、对用户数据进行解析,得到程序名称以及参数信息[-l]和[-a];
3、创建子进程,在子进程中进行程序替换;
4、shell程序需要等待子进程退出;

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

#define CLEAR_REDIRECT 1 //清空重定向
#define APPEND_REDIRECT 2 //追加重定向

char g_buf[1024]={ 0 }; //输入缓冲区
int g_redirect_flag = 0;//解析重定向标志
char* g_filename = NULL;//重定向文件名

void AnalyseFilename();//解析重定向
void AnalyseOrder(char** argv);//解析命令
void GetData(char** argv);//从标准输入获取要解析的命令

void AnalyseFilename()//解析输入字符串,若为重定向命令,获得重定向文件名
{
    char* ptr = g_buf;
    while(*ptr)
    {
        if(*ptr == '>')
        {
            //若找到重定向标志'>'将buf中的这个字符置为结束标志,下面命令解析时就不在解析
            g_redirect_flag++;
            *ptr = '\0';
            ptr++;

            if(*ptr == '>')
            {
                g_redirect_flag++;
                ptr++;
            }

            for(;isspace(*ptr) && *ptr != '\0'; ptr++);//找到文件名开始,出掉中间的不可见字符
            g_filename = ptr;

            for(;!isspace(*ptr) && *ptr != '\0'; ptr++);//文件名结束标志置为'\0'
            *ptr = '\0';
        }
        ptr++;
    }
}

void AnalyseOrder(char**argv)//解析命令
{
    char *ptr = g_buf;
    int i, argc = 0;

    while(*ptr)//按照空格对字符串进行切割
    {
        if(!isspace(*ptr))
        {
            argv[argc] = ptr;
            argc++;

            while(!isspace(*ptr) && *ptr != '\0')//到下一个空格且不是字符串结尾位置
            {
                ptr++;
            }
            if (*ptr == '\0')//解析结束
            {
                break;
            }

            *ptr = '\0';
        }
        ptr++;
    }
}

void GetData(char** argv)
{
    g_redirect_flag = 0;//每次进入解析,先将所有的全局变量初始化,避免解析上次留下数据
    g_filename = NULL;
    memset(g_buf, 0x00, 1024);

    printf("[username@locathost]$ ");
    fflush(stdout);
    
    fgets(g_buf,1023,stdin);//从标准输入获取数据
    g_buf[strlen(g_buf)-1] = '\0';
    
    AnalyseFilename();
    AnalyseOrder(argv);
}

int main()
{
    while(1)
    {
        char* argv[32]={NULL};
        int i;
        GetData(argv);

        pid_t pid = fork();

        if(pid < 0)//创建失败继续创建
        {
            continue;
        }
        else if(pid == 0)//子进程程序替换
        {
            if(g_filename != NULL)
            {
                int fd = -1;
                if(g_redirect_flag == CLEAR_REDIRECT)//清空重定向
                {
                    fd = open(g_filename,O_WRONLY|O_CREAT|O_TRUNC,0664);
                    if(fd < 0)
                    {
                        perror("open error:");
                        return -1;
                    }
                    dup2(fd,1);
                }

                else if(g_redirect_flag == APPEND_REDIRECT)//追加重定向 
                {
                    fd = open(g_filename,O_WRONLY|O_CREAT|O_APPEND,0664);
                    if(fd < 0)
                    {
                        perror("open error:");
                        return -1;
                    }
                    dup2(fd,1);
                }
            }
            execvp(argv[0],argv);
            exit(0);
            //子进程和父进程代码一致,若程序替换失败,
            //子进程就变成了新的shell,一个终端不需要有多个shell
            //因此替换失败,直接退出。
        }
        wait(NULL);//父进程等待,直至minishell退出
    }
    return 0;
}
发布了77 篇原创文章 · 获赞 16 · 访问量 6508

猜你喜欢

转载自blog.csdn.net/weixin_43886592/article/details/103959903
今日推荐