#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#define SIZE 1024 //字符串大小
#define SEP " " //以空格为分隔符
#define MAX_ARGC 64 //指令集中最多可以存储的指令的个数
char *argv[MAX_ARGC]; //指令集
char pwd[SIZE]; //存储
char env[SIZE];
int lastcode = 0; //存储获取到的退出码
//获取当前主机名
const char* HostName()
{
char* hostname = getenv("HOSTNAME");
if(hostname)
{
return hostname;
}
else{
return "none";
}
}
//获取当前用户
const char* User()
{
char* user = getenv("USER");
if(user)
{
return user;
}
else{
return "none";
}
}
//获取当前工作目录
const char* Pwd()
{
char* pwd = getenv("PWD");
if(pwd)
{
return pwd;
}
else{
return "none";
}
}
//获取家目录
char* Home()
{
return getenv("Home");
}
//人机交互
int Interactive(char commandline[])
{
//输出提示符
printf("[%s@%s %s]$ ",User(),HostName(),Pwd());
//获取用户输入的命令字符串
fgets(commandline,SIZE,stdin);
//如果获取到的是空串
commandline[strlen(commandline)-1] = 0;
return strlen(commandline);
}
//对字符串进行分隔
void Split(char commandline[])
{
int i = 0;
argv[i++] = strtok(commandline,SEP);
//strto函数在每一次调用之后,会记录后续遗留未处理的数据,下次调用的时候,以上次调用结束的位置作为下次调用开始的位置
while(argv[i++] = strtok(NULL,SEP));
if(strcmp(argv[0],"ls") == 0)
{
argv[i-1] = (char*)"--color";
argv[i] = NULL;
}
}
//创建子进程,让子进程执行接收到的指令
void Execute()
{
pid_t id = fork();
if(id == 0)
{
execvp(argv[0],argv);
}
int status = 0;
pid_t rid = waitpid(id,&status,0);
if(id==rid)
{
lastcode = WEXITSTATUS(status);
}
}
//内建命令,内建命令是指由shell自身直接实现并且提供的命令,而不是通过后外部程序或者子进程执行的命令。
//检测是否是内建指令,如果是内建指令,单独处理
//内建命令:cd、export、echo、set、exit、......
int BUildinCmd()
{
//检测是否是内建命令,初始值为0,如果是内建命令,则设置为1
int ret = 0;
if(strcmp("cd",argv[0]) == 0)
{
ret = 1;
//提取cd后的指令
char* target = argv[1];
//判断cd后是否输入了指令,如果没有指令,则为NULL
//当cd后没有跟选项的时候,cd会使得工作目录直接跳转到当前用户的家目录
if(!target)
target = Home();
//更改当前进程的工作目录
chdir(target);
char temp[SIZE];
//获取当前进程的工作目录
getcwd(temp,SIZE);
//将获取到的当前进程的工作目录写入到pwd中
snprintf(pwd,SIZE,"PWD=%s",temp);
//修改环境变量中的PWD
putenv(pwd);
}
else if(strcmp("export",argv[0]) == 0)
{
ret = 1;
if(argv[1])
{
strcpy(env,argv[1]);
putenv(env);
}
}
else if(strcmp("echo",argv[0]) == 0)
{
ret = 1;
if(argv[1] == NULL)
{
printf("\n");
}
else
{
if(argv[1][0] == '$')
{
if(argv[1][1] == '?')
{
printf("%d\n",lastcode);
lastcode = 0;
}
else
{
char *e = getenv(argv[1]+1);
if(e)
{
printf("%s\n",e);
}
}
}
else
{
printf("%s\n",argv[1]);
}
}
}
return ret;
}
int main()
{
while(1)
{
//存储获取到的用户输入的命令字符串
char commandline[SIZE];
int n = 0;
//1.打印命令提示符,获取用户输入的命令字符串
n = Interactive(commandline);
if(n==0)
continue;
//2.对命令行字符串进行切割
Split(commandline);
//3.处理内建命令
n = BUildinCmd();
if(n==1)
continue;
//4.执行这个命令
Execute();
}
return 0;
}
Linux详解:简单实现shell
最新推荐文章于 2024-11-07 10:17:21 发布
这篇文章详细描述了一个简单的C语言实现的shell,它接收用户输入的命令,进行字符串分割,处理内建命令如cd、export和echo,以及通过fork和execvp执行外部指令。
摘要由CSDN通过智能技术生成