Linux实现简易shell

编程入门 行业动态 更新时间:2024-10-09 21:26:28

Linux实现<a href=https://www.elefans.com/category/jswz/34/1769136.html style=简易shell"/>

Linux实现简易shell

文章目录

    • 🦄0. shell
    • 🐮1. 交互及获取命令行
    • 🐷2. 解析命令行
    • 🐯3. 执行命令行
      • 🐅3.1 普通命令
      • 🐅3.2 内建命令
    • 🦁4. 主函数逻辑及演示

本章代码gitee仓库:简易shell

🦄0. shell

shell是操作系统外的一层外壳程序,负责将用户的指令执行,将指令获取到之后再交给操作系统,操作系统将指令执行完毕之后的结果通过shell交给用户。shell/bash也是一个进程,本质上也是通过创建子进程来执行这些指令。

🐮1. 交互及获取命令行

我们先来开一下交互及我们输入的命令行格式

先来做交互的页面,这其实就是一个while循环,一直等着我们输入指令,我们可以通过获取环境变量来获取这些信息。

#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
const char *getUserName()
{return getenv("USER");
}
const char *getHostName()
{return getenv("HOSTNAME");
}
void getPwd()
{getcwd(pwd,sizeof(pwd));
}
void interact(char *cline, int size)
{getPwd();printf(LEFT"%s@%s %s"RIGHT""LABLE" ",getUserName(),getHostName(),pwd);char *s = fgets(cline,size,stdin);	//获取指令assert(s);(void)s;  //防止后面不使用s变量报警告,假装用一下cline[strlen(cline)-1] = '\0';  //将回车抵消//printf("%s\n",s);
}

我们可以输出我们获取的命令测试一下

🐷2. 解析命令行

获取到命令之后,我们就要解析这个命令,这个解析的本质上,就是将获取的字符串进行分割,分割各个部分:要执行的命令所带的命令行参数

例如ls -a -l,我们就需要解析成:

  • 所需执行的命令:ls
  • 命令行参数:-a-l
#define DELIM " \t"
int splitString(char cline[], char *_argv[])
{int i = 0;_argv[i++] = strtok(cline,DELIM);while(_argv[i++] = strtok(NULL,DELIM));return i-1;
}

🐯3. 执行命令行

获取到所需执行的命令和参数之后,其实就是创建子进程,然后程序替换来执行这个命令,但是这些命令分为普通命令和内建命令:

  • 普通命令:创建子进程直接程序替换
  • 内建命令:父进程自己执行

🐅3.1 普通命令

这里没有什么高科技,就是简单的创建子进程、程序替换和进程等待

#define EXIT_CODE 11
void normalExcute(char *_argv[])
{pid_t id = fork();if(id < 0){perror("fork fail");return; }else if(id == 0){//子进程执行命令//execvpe(_argv[0],_argv,environ);  //直接程序替换execvp(_argv[0],_argv);   //直接替换程序exit(EXIT_CODE);  //替换失败的退出码}else{//父进程等待子进程退出int status = 0;pid_t rid = waitpid(id,&status,0);  //阻塞等待if(rid == id){lastcode = WEXITSTATUS(status);}}
}

🐅3.2 内建命令

对应内建命令,需要我们自己去一个一个添加然后判断,这里做一个简单的演示

int buildCommand(char *_argv[], int _argc)
{if(_argc == 2 && strcmp(_argv[0],"cd") == 0){chdir(_argv[1]);getPwd();sprintf(getenv("PWD"),pwd);return 1;}else if(_argc == 2 && strcmp(_argv[0],"export") == 0) //导环境变量{putenv((char*)_argv[1]);return 1;}else if(_argc == 2 && strcmp(_argv[0],"echo") == 0)                                 {if(strcmp(_argv[1],"$?")==0){printf("%d\n",lastcode);lastcode = 0;}else if(*_argv[1] == '$'){char*val = getenv(_argv[1]+1);if(val) printf("%s\n",val);}else  printf("%s\n",_argv[1]);return 1;}//将ls命令显示颜色if(strcmp(_argv[0],"ls") == 0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}

🦁4. 主函数逻辑及演示

这里我们全部都封装起来了,各个模块解耦,想要修改的话,也很方便,完整的代码可以去仓库里面查看。

#define LINE_SIZE 1024
#define ARGC_SIZE 32int main()
{while(!quit){//交互 获取命令行interact(commandline,sizeof(commandline));//解析命令行int argc = splitString(commandline,argv);if(argc == 0) continue;//for(int i=0;argv[i];i++) printf("%s\n",argv[i]);//printf("%s\n",argv);//普通命令执行int flag = buildCommand(argv,argc);if(!flag) normalExcute(argv);}return 0;
}


所以我们每次登录的时候,界面会显示这些信息,其实就是因为系统启动了一个shell进程。

更多推荐

Linux实现简易shell

本文发布于:2023-11-16 23:30:46,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1635687.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:简易   Linux   shell

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!