【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;
}
相关推荐
JUNAI_Strive_ving4 分钟前
力扣6~10题
算法·leetcode·职场和发展
skywalk816310 分钟前
install fcitx chinese input at FreeBSD14.1
运维·服务器·freebsd
小羊在奋斗17 分钟前
【Linux】包管理器、vim详解及简单配置
linux·运维·vim
洛临_25 分钟前
【C语言】基础篇续
c语言·算法
戊子仲秋25 分钟前
【LeetCode】每日一题 2024_10_7 最低加油次数(堆、贪心)
算法·leetcode·职场和发展
CS_素锦少年25 分钟前
Linux_kernel字符设备驱动12
linux·运维·服务器
NineOne_豆浆狂魔29 分钟前
Linux 缓冲区
linux·服务器·c
醉颜凉1 小时前
银河麒麟服务器操作系统中查询服务器主板型号
运维·操作系统·国产化·kylin os·银河麒麟桌面操作系统
陈序缘1 小时前
Go语言实现长连接并发框架 - 消息
linux·服务器·开发语言·后端·golang
mysql学习中1 小时前
Linux的环境变量
linux·运维·服务器·tcp/ip·centos