linux高编进程------支持外部命令的shell实现(glob、strsep、fork)

简单实现一个可以支持外部命令的shell:

/*****************************
 *功能:实现一个简单的shell
 *终端:./shell
 *      可以输入pwd等外部命令测试
 * **************************/

/*******包含头文件********/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <glob.h>

/*******提取DELIMS分隔符*******/
#define DELIMS  " \t\n"

/********创建命令结构体(方便扩展)**********/
struct cmd_st
{
    glob_t globres ;
};

/********打印终端的提示*********/
static void prompt(void)
{
    printf("mysh-0.1$ ");
}
/***********************************
 *功能:解析终端输入的命令行
 *      参数:line:从终端获取的命令行
 *            res:解析的命令行(回填)
 * ********************************/
static void parse(char *line,struct cmd_st *res)
{
    char *tok ;
    int i = 0 ;
    while(1)
    {
        //1.从终端截取命令字符串(line为指向欲分割的字符串,DELIM为分隔符,函数将返回分隔符前面的字符串,tok将指向分隔符之后的字符串)
        tok = strsep(&line,DELIMS);
        //2.如果解析失败跳出循环
        if(tok == NULL)
            break ;
        //3.当多个分割符连续可能出现空串则继续
        if(tok[0] == '\0')
            continue ;
        /*********************************************************
         * 4.取得的每个字符串都应该保存(由于命令长度不确定,所以一定要变长)
         *  所以用glob中的gl_pathv存储
         *  flag:GLOB_NOCHECK:如果没有任何内容匹配tok,返回tok
         *        GLOB_APPEND:第一次不追加,以后追加(不加会覆盖)
         *  存储结果放到res->globres中
         *  ******************************************************/
        glob(tok,GLOB_NOCHECK | GLOB_APPEND*i ,NULL,&res->globres);
        i = 1 ;
    }
}

int main()
{
    //1.如果使用getline,一定要初始化
    char *linebuf = NULL ;
    size_t linebuf_size = 0 ;

    struct cmd_st cmd ;
    pid_t pid ;

    while(1)
    {   //2.打印终端
        prompt();
        //3.获取字符串
        if(getline(&linebuf ,&linebuf_size,stdin) < 0)
            break;
        //4.解析字符串,结果放到cmd.globres.gl_pathv中
        parse(linebuf,&cmd);

        if(0){}//内部命令
        else
        {   //5.外部命令:创建子进程
            pid = fork();
            if(pid < 0)
            {
                perror("fork()");
                exit(1);
            }
            //6.子进程用新进程替换当前进程
            if(pid == 0)
            {
                execvp(cmd.globres.gl_pathv[0],cmd.globres.gl_pathv);
                perror("execvp");
                exit(1);
            }
            else
            {   //7.父进程收尸
                wait(NULL);
            }
        }
    }
    exit(0);
}                                                                                                                                    
posted @ 2016-03-18 11:29  muzihuan  阅读(626)  评论(0编辑  收藏  举报