当前位置: 首页 > news >正文

[Linux入门]---使用exec函数实现简易shell

文章目录

  • 1.简易实现
  • 2.人机交互,获取命令行
  • 3.命令行分割
  • 4.执行命令
  • 5.内建命令
  • 6.myshell代码

1.简易实现

2.人机交互,获取命令行

代码如下:

int quit=0;
#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define LINE_SIZE 1024char pwd[LINE_SIZE];
char commandline[LINE_SIZE];const char* getusername()
{return getenv("USER");
}void getpwd()
{getcwd(pwd, sizeof(pwd));
}
void interact(char* cline, int size)
{//获取主机名char hostname[256];gethostname(hostname, sizeof(hostname));//获取当前路径getpwd();printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(),hostname, pwd);char* s = fgets(cline, size, stdin);assert(s);//debug版本下assert才起效果//release,assert失效(void)s;//使用一下,可以在不同版本都生效,抵挡编译器报警//"abcd\n\0"cline[strlen(cline)-1] = '\0';
}
int main()
{while(!quit){//交互问题,获取命令行interact(commandline,sizeof(commandline));printf("%s\n",commandline );}return 0;
}

代码运行的的结果为:
在这里插入图片描述
运行结果如上,程序获取命令行以及提示行显示的功能已经完成了。

3.命令行分割

代码如下:

#define DELIM " "
#define ARGC_SIZE 32char* argv[ARGC_SIZE];int splitstring(char cline[], char* _argv[])
{int i = 0;_argv[i++] = strtok(cline, DELIM);//stork函数扫描字符串末尾时,返回空指针while(_argv[i++] = strtok(NULL,DELIM));//故意写的=return i - 1;
}
int main()
{while(!quit){//交互问题,获取命令行interact(commandline,sizeof(commandline));//3.子串分割问题,解析命令行int argc = splitstring(commandline,argv);if(argc == 0) continue;for(int i = 0; i < argc; i++){printf("%s\t",argv[i]);}printf("\n");}return 0;
}

代码运行的的结果为:
在这里插入图片描述
运行结果如上,命令行分割成字符串并存放进入数组使用。

4.执行命令

代码如下:

#define EXIT_CODE 44int lastcode = 0;void NormalExcute(char* _argv[])
{pid_t id = fork();if(id < 0){perror("fork");return;}else if(id == 0){//让子进程执行命令execvp(_argv[0],_argv);exit(EXIT_CODE);}else{int status = 0;pid_t rid = waitpid(id, &status,0);if(rid == id){lastcode = WEXITSTATUS(status);}}
}
int main()
{while(!quit){//1.交互问题,获取命令行interact(commandline,sizeof(commandline));//2.子串分割问题,解析命令行int argc = splitstring(commandline,argv);if(argc == 0) continue;for(int i = 0; i < argc; i++){//printf("%d:",i);//printf("%s\n",argv[0]);printf("%s\n",argv[i]);}printf("\n");//3.普通命令的执行//if(!n)NormalExcute(argv);}return 0;
}

代码运行的结果:
在这里插入图片描述
运行结果如上,可以让子进程执行替换函数,调用系统程序命令执行!

5.内建命令

在这里插入图片描述
我们发现使用一些命令的时候没有结果,诸如“”cd\echo”等命令,因为这些命令属于内建命令,是要父进程执行的。
代码如下:

#define EXIT_CODE 44int lastcode = 0;//自定义环境变量表
char myenv[LINE_SIZE];
//自定义本地变量表int buildCommand(char* _argv[], int _argc)
{if(_argc == 2 && strcmp(_argv[0], "cd") == 0){//修改父进程中的当前路径chdir(argv[1]);//把修改路径放到pwd数组中getpwd();//把pwd数组的路径,放到环境变量中sprintf(getenv("PWD"), "%s", pwd);return 1;}else if(_argc == 2 && strcmp(_argv[0], "export") == 0){strcpy(myenv, _argv[1]);putenv(myenv);//增加环境变量到父进程中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);}return 1;}//特殊处理一下if(strcmp(_argv[0], "ls") == 0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}
int main()
{while(!quit){//1.交互问题,获取命令行interact(commandline,sizeof(commandline));//2.子串分割问题,解析命令行int argc = splitstring(commandline,argv);if(argc == 0) continue;for(int i = 0; i < argc; i++){//printf("%d:",i);//printf("%s\n",argv[0]);printf("%s\n",argv[i]);}printf("\n");//指令的判断//内建命令,本质就是一个shell内部的一个函数int n = buildCommand(argv, argc);//3.普通命令的执行if(!n) NormalExcute(argv);}return 0;
}

代码运行的结果如下:
在这里插入图片描述
在执行普通命令之前,我们需要判断是不是内建命令,如果是的话,分析之后让父进程执行!

6.myshell代码

#include <stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define LINE_SIZE 1024
#define DELIM " "
#define ARGC_SIZE 32
#define EXIT_CODE 44int quit=0;
char pwd[LINE_SIZE];
char commandline[LINE_SIZE];
char* argv[ARGC_SIZE];
int lastcode = 0;//自定义环境变量表
char myenv[LINE_SIZE];
//自定义本地变量表const char* getusername()
{return getenv("USER");
}
//const char* gethostname()
//{
//    return getenv("HOSTNAME");
//}
const char* mygethostname()
{//char myhostname[LINE_SIZE];return getenv("HOSTNAME");
}
void getpwd()
{getcwd(pwd, sizeof(pwd));
}
void interact(char* cline, int size)
{//获取主机名char hostname[256];gethostname(hostname, sizeof(hostname));//获取当前路径getpwd();//printf("%s\n",mygethostname());//printf(LEFT"%s@%s%s"RIGHT""LABLE" ",getusername(),mygethostname(),pwd);printf(LEFT"%s@%s %s"RIGHT""LABLE" ", getusername(),hostname, pwd);char* s = fgets(cline, size, stdin);assert(s);//debug版本下assert才起效果//release,assert失效(void)s;//使用一下,可以在不同版本都生效,抵挡编译器报警//"abcd\n\0"cline[strlen(cline)-1] = '\0';
}int splitstring(char cline[], char* _argv[])
{int i = 0;_argv[i++] = strtok(cline, DELIM);//stork函数扫描字符串末尾时,返回空指针while(_argv[i++] = strtok(NULL,DELIM));//故意写的=return i - 1;
}void NormalExcute(char* _argv[])
{pid_t id = fork();if(id < 0){perror("fork");return;}else if(id == 0){//让子进程执行命令execvp(_argv[0],_argv);exit(EXIT_CODE);}else{//创建子进程失败int status = 0;pid_t rid = waitpid(id, &status,0);if(rid == id){lastcode = WEXITSTATUS(status);}}
}
int buildCommand(char* _argv[], int _argc)
{if(_argc == 2 && strcmp(_argv[0], "cd") == 0){//修改父进程中的当前路径chdir(argv[1]);//把修改路径放到pwd数组中getpwd();//把pwd数组的路径,放到环境变量中sprintf(getenv("PWD"), "%s", pwd);return 1;}else if(_argc == 2 && strcmp(_argv[0], "export") == 0){strcpy(myenv, _argv[1]);putenv(myenv);//增加环境变量到父进程中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);}return 1;}//特殊处理一下if(strcmp(_argv[0], "ls") == 0){_argv[_argc++] = "--color";_argv[_argc] = NULL;}return 0;
}
int main()
{while(!quit){//1.交互问题,获取命令行interact(commandline,sizeof(commandline));//2.子串分割问题,解析命令行int argc = splitstring(commandline,argv);if(argc == 0) continue;//指令的判断//内建命令,本质就是一个shell内部的一个函数int n = buildCommand(argv, argc);//3.普通命令的执行if(!n) NormalExcute(argv);}return 0;
}

http://www.mrgr.cn/news/27025.html

相关文章:

  • Python基础语法(3)上
  • MySQL 表的增删改查
  • 多模态学习
  • 概述03 A/B test
  • 从关键新闻和最新技术看AI行业发展(第三十一期2024.8.26-9.8) |【WeThinkIn老实人报】
  • Linux——进程状态
  • Linux内核编译并移植至ARM平台
  • 跨平台互斥体封装
  • 数据结构:单链表
  • 前端必知必会-响应式网页设计Viewport和GridView
  • 家庭理财管理系统
  • 【极限、数学】 NOIP 2018 提高组初赛试题 第 7 题详解(线段长度期望)
  • 【代码随想录训练营第42期 Day58打卡 - 图论Part8 - 拓扑排序
  • 【免费资料推荐】数据资产管理实践白皮书(6.0版)
  • 每天五分钟玩转深度学习PyTorch:模型参数优化器torch.optim
  • 智能工厂的设计软件 之 语言设计
  • 【Jetson】Jetson Orin NX刷机教程
  • nacos和eureka的区别详解
  • Linux sh命令
  • 完结马哥教育SRE课程--就业篇