[Linux]简单的shell实现

一个简单的shell实现

什么是内建命令

内建命令是由shell本身提供的命令,而不是通过外部程序(如位于/bin/usr/bin等目录下的可执行文件)来执行的命令。这些命令在shell启动的时候就加载到内存中,执行效率相对较高。

常见的内建命令有:cdpwdecho

什么是当前路径

本质就是进程的工作目录,默认是进程在哪个目录底下执行,它的工作目录就是这个目录。

那这个工作目录可以更改吗?答案是可以的,使用chdir()函数就可以更改当前进程的工作目录。

在我们自己实现一个简单的shell,执行cd命令的时候,你会发现路径没有变化。那是因为在执行命令的时候,我们是使用fork()出来的子进程来执行的cd,子进程有自己的工作目录(一般和父进程的工作目录相同),当执行cd的时候,更改的是子进程的目录,子进程执行完毕,什么都没了,继续用的是父进程,即shell。

简单的shell实现

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

#define NUM 1024
#define OP_NUM 64

char command[NUM];
char *myargv[OP_NUM];
int lastCode = 0;
int lastSig = 0;

int main()
{
    while (1)
    {
        char *user = getenv("USER");
        char *host = getenv("HOSTNAME");
        printf("%s@%s 当前路径#", user, host);
        fflush(stdout);

        char *s = fgets(command, sizeof(command) -1, stdin);//获取命令行的输入
        assert(s != NULL);
        (void)s;
        //清除用户按下的回车
        command[strlen(command) - 1] = 0;

        //字符串切割
        myargv[0] = strtok(command, " ");
        int i = 1;

        //显示颜色
        if (myargv[0] != NULL && strcmp(myargv[0], "ls") == 0) 
        {
            myargv[i++] = (char*)"--color=auto";
        }

        //myargv[] 必须以NULL结尾,而strtok函数结束的时候返回NULL
        //strtok()中的NULL表示从上次结束的位置继续查找下一个子串
        while (myargv[i++] = strtok(NULL, " ")) {}

        //不需要创建子进程,让shell自己执行对应的命令
        if (myargv[0] != NULL && strcmp(myargv[0], "cd") == 0)
        {
            if (myargv[1] != NULL) chdir(myargv[1]);
            continue;
        }
        if (myargv[0] != NULL && myargv[1] != NULL && strcmp(myargv[0], "echo") == 0)
        {
            if (strcmp(myargv[1], "$?") == 0) printf("%d, %d\n", lastCode, lastSig);
            else printf("%s\n", myargv[1]);
            continue;
        }
        
        //创建子进程
        pid_t id = fork();
        assert(id != -1);

        if (id == 0)
        {
            //程序替换
            execvp(myargv[0], myargv);
            exit(1);
        }
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        assert(ret > 0);
        (void)ret;

        lastCode = WEXITSTATUS(status);
        lastSig = WIFEXITED(status);

    }
}
posted @ 2024-11-25 19:44  羡鱼OvO  阅读(30)  评论(0)    收藏  举报