实现一个简单shell(支持重定向)

5.16更新:支持重定向

我们知道对于Linux,shell就是个命令行解释器,当我们输入相关的命令,会去执行相关的操作。

比如当我们输入ls -a -l命令,shell就会打印出当前目录的内容,这是如何实现的?shell自己就是一个进程,当我们输入ls之类的命令,它会通过fork,exec函数去创建一个新的子进程去执行相关操作。因此我们也可以利用这个来实现一个简单的shell。

当然,这个shell足够简单,并不能像Linux内置的shell那么强大支持各种操作,报错,等等。

先来看看实现后的效果图:

这里写图片描述

红色圈起来的是系统本身的shell,而蓝色则是我自己模拟实现的一个简单shell,可以看到当我输入ls命令,它也完成打印操作,输入./hello也成功执行了hello程序输入hello。当然,类似管道等操作并没有实现,具体可以参考shell去进一步了解。

下面我们来聊聊如何实现简单shell:

  1. 首先是提示符,xuyang@host以及当前路径,这个可以调用系统api直接获取打印,这里为了简便,我直接用了printf实现。
  2. 解析命令,对于ls -a -l这种命令解析,我们只需要将存入到指针数组中,char* shell _ argv[32],ls存到shell _ argv[0] ,-a存到shell _ argv[1],-l存入到shell _ argv[2] 。。。最后一个设置为NULL
  3. 利用exev调用新的程序

代码如下:

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




int main()
{
    for (;;)
    {
        printf("myshell@host:");
        fflush(stdout);

        //解析输入到shell上的字符串 ls   -a -l
        char buffer[1024];
        int read_size = read(1, buffer, sizeof(buffer));
        if (read_size > 0)
        {
            buffer[read_size - 1] = 0;
        }

        char* shell_argv[32] = {NULL};
        int shell_index = 0;
        char* start = buffer;
        while (*start != '\0')
        {
            while (*start != '\0' && isspace(*start))
            {
                *start = '\0';
                start++;
            }
            shell_argv[shell_index++] = start;
            while (*start != '\0' && !isspace(*start))
            {
                start++;
            }
        }

        //创建子进程来exec

        pid_t pid = vfork();

        if (pid < 0)
        {
            printf("vfork failure\n");
            exit(1);
        }
        else if (pid == 0)
        {
            //考虑重定向 > 
            //在字符串数组中找重定向标志

            int i = 0;

            int flag = 0;

            for (; shell_argv[i] != NULL; ++i )
            {
                if (strcmp(">", shell_argv[i]) == 0)
                {
                    flag = 1;
                    break;
                }
            }

            int copyFd;

            shell_argv[i] = NULL;


            if (flag)
            {
                if (shell_argv[i+1] == NULL)
                {
                    printf("command error\n");
                    exit(1);
                }

                close(1);

                int fd = open(shell_argv[i+1], O_WRONLY | O_CREAT, 0777);

                copyFd = dup2(1, fd);
            }

            execvp(shell_argv[0], shell_argv);

            if (flag)
            {
                close(1);
                dup2(copyFd, 1);

            }

            exit(1);
        }
        else //father process
        {
            int status = 0;
            int ret = waitpid(pid, &status, 0);
            if (ret == pid)
            {
                if (WIFEXITED(status))
                {
                   // printf("exitCode is %d\n", WEXITSTATUS(status));
                }
                else if (WIFSIGNALED(status))
                {
                    printf("signal is %d\n", WTERMSIG(status));
                }
            }
        }

    }
    return 0;
}

效果如下图:

这里写图片描述

  • 4
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值