Linux-my_bash(cd)

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

#define LEN 10
char* Cmd[LEN] = {0};//定义全局变量 用来存储分割后用户命令
int count = 0;
char OLDPWD[1024] = {0};//定义全局变量 环境变量,用于存储更新的环境变量 cd-



//命令提示符的输出:用户名+主机名+当前目录名+区别用户类型的符号
void out_flag()
{
    char flag = '$';//用户类型区别符号,普通用户
    struct passwd *pw = getpwuid(getuid());//通过用户的UID查找用户的passwd的数据(getuid() 获取用户的UID)

    if(getuid() == 0)//当使用root 身份执行,
    {
        flag = '#';
    }

    struct utsname host;
    uname(&host);
    char *hostname = strtok(host.nodename, ".");//切割目录的节点信息,获取目录名

    char path[128] = {0};
    getcwd(path, 127);//获取当前目录的绝对路径

    char *p = strtok(path, "/");//用‘/’切割字符串
    char *nowdir = NULL;//
    while(p!= NULL)
    {
        nowdir = p;
        p = strtok(NULL, "/");
    }

    if(nowdir == NULL)
    {
        nowdir = "/";
    }
    if(strcmp(nowdir, pw->pw_name) == 0)
    {
        nowdir = "~";
    }

    printf("[%s@%s %s]mybash%c ", pw->pw_name, hostname,
            nowdir, flag);
    fflush(stdout);
},

//切割用户命令,并存放在Cmd[]
void cut_cmd(char *cmd)
{
    char *p = strtok(cmd, " ");
    while(p != NULL)
    {
        Cmd[count++] = p;
        p = strtok(NULL, " ");
    }
}

//特殊符号的处理 cd    exit 
int special_cmd()
{
    if(strncmp("cd", Cmd[0], 2) == 0)//输入 cd 
    {
        if(Cmd[1] == NULL || strncmp(Cmd[1], "~", 1) == 0)//cd  cd ~回到当前目录的家目录
        {
            struct passwd *pw = getpwuid(getuid());
            Cmd[1] = pw->pw_dir;
        }
        else if(strncmp(Cmd[1], "-", 1) == 0)//cd - 回到上一个目录并显示当前目录
        {
            //切换到家目录到上一次所在目录
            if(strlen(OLDPWD) == 0)//刚登录shell是环境变量OLDPWD中是没有记录的  OLDPWD=0
            {
                printf("mybash: cd :: OLDPWD not set\n");
                return 1;
            }

            Cmd[1] = OLDPWD;//将上次目录存放在Cmd[1]
            printf("%s\n", Cmd[1]);//输出当前目录(上次目录)
        }

        char str[1024] = {0};//str存放当前路径
        getcwd(str, 1023);//在切换当前目录之前保存路径
        chdir(Cmd[1]);    // 切换路径到Cmd[1]
        strcpy(OLDPWD, str);//更新环境变量

        return 1;
    }
    if(strncmp("exit", Cmd[0], 4) == 0)//输入exit
    {
        exit(0);
    }

    return 0;
}

void clear_cmd()//清空Cmd[]函数
{
    int i = 0;
    for(;i < count; ++i)
    {
        Cmd[i] = 0;
    }

    count = 0;
}

void main()
{
    while(1)
    {
        out_flag();
        char cmd[128] = {0};
        fgets(cmd, 128, stdin); //获取命令
        cmd[strlen(cmd) - 1] = 0; //去掉最后一个回车符

        if(strlen(cmd) == 0) // 判别用户的无效输入
        {
            continue;
        }

        cut_cmd(cmd); // 切割cmd

        int res = special_cmd(); // 判别是否是需要集成到bash中的特殊命令
        if(res == 1)
        {
            clear_cmd(); //清空全局的指针数组,并将count归0
            continue;
        }

        pid_t pid = fork();
        assert(pid != -1);

        if(pid == 0)
        {
            // 用命令的可执行文件(./mybin)替换当前进程
            char path[1024] = "/home/stu/mydir/LG1702shell/mybin/";
            if(strstr(Cmd[0], "/") != NULL)//用户直接输入指定路径
            {
                memset(path, 0, 1024);//清空path
            }
            strcat(path, Cmd[0]);//将用户指定目录链接到cd 后

            execv(path, Cmd);//用path下名为Cmd的应用程序替换子进程,执行成功,execv无返回值
            printf("mybash: %s : command not found\n", Cmd[0]);
            exit(0);
        }
        else
        {
            wait(NULL);//等待子进程结束
        }

        clear_cmd();
    }
}
码片

猜你喜欢

转载自blog.csdn.net/s_yj_q/article/details/78125582
今日推荐