【Linux】手搓shell

手搓shell

代码

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>


#define ZERO '\0'
#define SIZE 512
#define SEP " "
#define NUM 32
#define Skiopath(p) do{ p += strlen(p-1);while(*p!='/')p--;}while(0)



char *gArgv[NUM];
char cwd[SIZE*2];
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 "None";
    return cwd;
}
void Makecommandline_print()
{
    char line[SIZE];
    const char *username = GetuserName();
    const char *hostname = GethostName();
    const char *cwd = GetCwd();
    Skiopath(cwd);
    snprintf(line,SIZE,"[%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 Splitcommand(char command[],size_t n)
{
    //"ls -a -l -n"-> "ls" "-a" "-l" "-n"
    gArgv[0] = strtok(command,SEP);
    int index =1;
    while((gArgv[index++]=strtok(NULL,SEP)));//done,故意写成=,表示先赋值,在判断。分割之后,strtok会返回NULL,刚好让gArgv最后一个元素是NULL,并且while判断结束

}

void Executecommand()
{

    pid_t id =fork();
    if(id<0) Die();
    else if(id==0)
    {
        //child
        execvp(gArgv[0],gArgv);
        exit(errno);
    }
    else{
        //father
        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);
            
        }
    }

}
void Cd()
{
    const char *path = gArgv[1];
    if(path==NULL)path=Gethome();
    //path 一定存在
    chdir(path);
    //刷新环境变量
    char temp[SIZE*2];
    getcwd(temp,sizeof(temp));
    //导环境变量
    snprintf(cwd,sizeof(cwd),"PWD=%s",temp);
    putenv(cwd);
}
int Checkbuilding()
{
    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;
}
int main()
{
    int quit =0 ;
    while(!quit)
    {
        //1.输出一个命令行
        Makecommandline_print();
        
        //2.获取用户命令字符串
        char usercommand[SIZE];
        int n = Getusercommand(usercommand,sizeof(usercommand));
        
        //3.命令行字符串分割
        Splitcommand(usercommand,sizeof(usercommand));
        
        //4.检查命令是否是内建命令
        n=Checkbuilding();
        if(n)continue;
        //n.执行命令
        Executecommand();

    }
    return 0;
}
相关推荐
CodeWithMe16 分钟前
【Note】《深入理解Linux内核》 Chapter 15 :深入理解 Linux 页缓存
linux·spring·缓存
0wioiw016 分钟前
Ubuntu基础(监控重启和查找程序)
linux·服务器·ubuntu
Tipriest_20 分钟前
Ubuntu常用的软件格式deb, rpm, dmg, AppImage等打包及使用方法
linux·运维·ubuntu
Orlando cron24 分钟前
数据结构入门:链表
数据结构·算法·链表
真智AI36 分钟前
利用 Claude Opus 4 自动化 GitHub 工作流:从安装到实战详解
运维·自动化·github
牛客企业服务1 小时前
2025年AI面试推荐榜单,数字化招聘转型优选
人工智能·python·算法·面试·职场和发展·金融·求职招聘
胡斌附体1 小时前
linux测试端口是否可被外部访问
linux·运维·服务器·python·测试·端口测试·临时服务器
愚润求学2 小时前
【Linux】自旋锁和读写锁
linux·运维
大锦终2 小时前
【Linux】常用基本指令
linux·运维·服务器·centos
IT项目管理2 小时前
达梦数据库DMHS介绍及安装部署
linux·数据库