Linux:简易Shell的实现

myshell.c

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>

#define SIZE 512
#define ZERO '\0'
#define SPACE " "
#define NUM 32
#define SkipPath(p) do{ p += (strlen(p)-1) ; while(*p != '/') p--; }while(0)
#define SkipSpace(cmd,pos) do{ while(1){ if(isspace(cmd[pos])) pos++; else break;} }while(0)

// "ls -a -l -n > myfile.txt"
#define None_Redir 0
#define In_Redir 1//输入
#define Out_Redir 2//输出
#define APP_Redir 3//追加

int redir_type=None_Redir;
char* filename=NULL;

char cwd[SIZE*2];
char *gArgv[NUM];
int lastcode = 0;

void Die()
{
    exit(1);
}

const char* GetHome()
{
    const char* home=getenv("HOME");
    if(home == NULL) return "/";
    return home;
}


const char* GetUserName()
{
    const char* name=getenv("USER");
    if(name == NULL) return "None";
    return name;
}


const char* GetHostName()
{
    const char* hostname=getenv("HOSTNAME");
    if(hostname == NULL) return "None";
    return hostname;
}

const char* GetCwd()
{
    const char* cwd = getenv("PWD");
    if(cwd == NULL) return "NULL";
    return cwd;
}

void MakeCommandLineAndPrint()
{
    char line[SIZE];
    const char *username = GetUserName();
    const char *hostname = GetHostName();
    const char *cwd = GetCwd();
    SkipPath(cwd);
    snprintf( line, sizeof(line), "[%s@%s %s]: ", username, hostname, strlen(cwd) == 1 ? "/" : cwd + 1 );
    printf("%s", line);
    fflush(stdout);
}

int GetUserCommand(char* command, size_t n)
{
    char* s = fgets(command,n,stdin);
    if(s == NULL) return -1;
    command[strlen(command)-1]=ZERO;
    return strlen(command);
}

void CheckRedir(char cmd[])
{
    // >: 输入重定向
    // <: 输出重定向
    // >>: 追加重定向
    int pos = 0;
    int end = strlen(cmd);
    while(pos<end)
    {
        if(cmd[pos] == '>')
        {
            if(cmd[pos+1] == '>')
            {
                cmd[pos++] = 0;
                pos++;
                redir_type = APP_Redir;
                SkipSpace(cmd,pos);
                filename = cmd + pos;
            }
            else{
                cmd[pos++] = 0;
                pos++;
                redir_type = Out_Redir;
                SkipSpace(cmd,pos);
                filename = cmd + pos;
            }
        }
        else if(cmd[pos] == '<')
        {
                cmd[pos++] = 0;
                pos++;
                redir_type = In_Redir;
                SkipSpace(cmd,pos);
                filename = cmd + pos;
        }
        else{
            pos++;
        }
    }
}
void SplitCommand(char* command, size_t n)
{
    (void)n;
    gArgv[0] = strtok(command,SPACE);
    int index = 1;
    while((gArgv[index++]=strtok(NULL,SPACE)));
}

void Cd()
{
    const char* path =gArgv[1];
    if(path == NULL) path = GetHome();
    chdir(path);
    char temp[SIZE*2];
    getcwd(temp,sizeof(temp));
    snprintf(cwd,sizeof(cwd),"PWD=%s",temp);
    putenv(cwd);
}

int CheckBuildin()
{
    int yes = 0;
    const char* enter_cmd = gArgv[0];
    if(strcmp(enter_cmd,"cd") == 0)
    {
        yes = 1;
        Cd();
    }
    else if((strcmp(enter_cmd,"echo") == 0) && (strcmp(gArgv[1],"$?") == 0))
    {
        yes = 1;
        printf("%d\n",lastcode);
        lastcode = 0;
    }
    return yes;
}

void ExecuteCommand()
{
    pid_t id = fork();
    if(id < 0) Die();
    else if(id == 0)
    {
        //设置重定向
        if(filename!=NULL)
        {
            if(redir_type==In_Redir)
            {
                int fd = open(filename,O_RDONLY);
                dup2(fd,0);
            }else if(redir_type == Out_Redir)
            {
                int fd = open(filename,O_WRONLY | O_CREAT | O_TRUNC, 0666);
                dup2(fd,1);
            }else if (redir_type == APP_Redir)
            {
                int fd = open(filename,O_WRONLY | O_CREAT | O_APPEND, 0666);
                dup2(fd,1);
            }else{}
        }
        execvp(gArgv[0],gArgv);
        exit(errno);
    }
    else
    {
        int status = 0;
        pid_t rid = waitpid(id, &status, 0);
        if(rid > 0)
        {
            lastcode = WEXITSTATUS(status);
            if(lastcode != 0) printf("%s:%s:%d\n", gArgv[0], strerror(lastcode), lastcode);
        }

    }
}

int main()
{
    while(1)
    {
        //0.先重置
        redir_type = None_Redir;
        filename = NULL;

        //1.自制命令行
        MakeCommandLineAndPrint();


         //2.获取用户指令字符串
        char usercommand[SIZE];
        int n = GetUserCommand(usercommand, sizeof(usercommand));
        if(n < 0) return 1;

         //2.5检查是否需要对指令进行重定向
        CheckRedir(usercommand);

        // 2.2 debug
//        printf("cmd: %s\n", usercommand);
//        printf("redir: %d\n", redir_type);
//        printf("filename: %s\n", filename);

        if(n <= 0) return 1;

         //3.对指令字符串进行分割
         SplitCommand(usercommand,sizeof(usercommand));

         //4.检查字符串是否是内建命令
         n = CheckBuildin();

         if(n) continue;

         //5.执行命令
        ExecuteCommand();
    }
    return 0;
}

用用看:

更多学习代码: XiangChao (RuofengMao) - Gitee.com

相关推荐
威迪斯特10 分钟前
CentOS图形化操作界面:理论解析与实践指南
linux·运维·centos·组件·图形化·桌面·xserver
张张努力变强14 分钟前
C++ STL string 类:常用接口 + auto + 范围 for全攻略,字符串操作效率拉满
开发语言·数据结构·c++·算法·stl
万岳科技系统开发14 分钟前
食堂采购系统源码库存扣减算法与并发控制实现详解
java·前端·数据库·算法
一方热衷.16 分钟前
在线安装对应版本NVIDIA驱动
linux·运维·服务器
小镇敲码人18 分钟前
探索CANN框架中TBE仓库:张量加速引擎的优化之道
c++·华为·acl·cann·ops-nn
独自归家的兔19 分钟前
ubuntu系统安装dbswitch教程 - 备份本地数据到远程服务器
linux·运维·ubuntu
张登杰踩20 分钟前
MCR ALS 多元曲线分辨算法详解
算法
ONE_SIX_MIX22 分钟前
ubuntu 24.04 用rdp连接,桌面黑屏问题,解决
linux·运维·ubuntu
平安的平安22 分钟前
面向大模型算子开发的高效编程范式PyPTO深度解析
c++·mfc
龙飞0522 分钟前
Systemd -systemctl - journalctl 速查表:服务管理 + 日志排障
linux·运维·前端·chrome·systemctl·journalctl