您的位置:首页 > 娱乐 > 明星 > [Linux入门]---使用exec函数实现简易shell

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

2024/12/23 16:40:40 来源:https://blog.csdn.net/m0_74288306/article/details/142061652  浏览:    关键词:[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;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com