简易的自定义Shell实现
1. 程序概述
首先,让我们了解一下这个自定义Shell的主要功能和结构。该Shell具有以下特点:
- 基本的命令解析和执行
- 内建命令支持(cd、export、echo)
- 获取用户名、主机名和当前工作目录显示
- 错误代码传递和显示
2. 主要函数解析
2.1 getcommand
int getcommand(char* command)
{
printf("[%s%s %s]# ",getUsername(),getHostname(),getPWDname());
char* r = fgets(command,MAXIN,stdin);
if(r == NULL) return 0;
command[strlen(command)-1] = '\0';
return 1;
}
此函数用于获取用户输入的命令,并将其存储在指定的字符数组中。它显示包含用户名、主机名和当前工作目录的命令提示符。
2.2 commandsplit
void commandsplit(char* in, char* out[])
{
int argc = 0;
out[argc++] = strtok(in,SEPARATOR);
while( out[argc++] = strtok(NULL,SEPARATOR));
return ;
}
commandsplit 函数将输入的命令字符串分割成命令和参数的数组,并用 SEPARATOR 定义的分隔符进行切割。
2.3 execute
void execute(char* agrv[])
{
pid_t id = fork();
if(id == 0)
{
execvp(agrv[0],agrv);
exit(1);
}
else
{
int status = 0;
pid_t rid = waitpid(id,&status,0);
if(rid > 0 )
{
lostcode = WEXITSTATUS(status);
}
}
}
execute 函数使用 fork 创建子进程,并在子进程中执行用户输入的命令。父进程等待子进程执行完成,并获取子进程的退出状态。
2.4 builtin
int builtin(char* argc[])
{
if(strcmp(argc[0],"cd") == 0)
{
cd(argc);
return 1;
}
else
{
printf("%s\n",getenv(e));
return 1;
}
return 0;
}
builtin 函数用于处理内建命令,如 cd、export 和 echo。它通过比较命令字符串来确定是否为内建命令,并调用相应的功能函数执行。
3. 完整程序
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAXIN 100
#define SIZE 100
#define SEPARATOR " "
int lostcode = 0;
char cwd[1024];
char env[1024];
char* getUsername()
{
return getenv("USER");
}
char* getHostname()
{
return getenv("HOSTNAME");
}
char* getPWDname()
{
return getenv("PWD");
}
int getcommand(char* command)
{
printf("[%s%s %s]# ",getUsername(),getHostname(),getPWDname());
char* r = fgets(command,MAXIN,stdin);
if(r == NULL) return 0;
command[strlen(command)-1] = '\0';
return 1;
}
void commandsplit(char* in,char* out[])
{
int argc = 0;
out[argc++] = strtok(in,SEPARATOR);
while( out[argc++] = strtok(NULL,SEPARATOR));
return ;
}
void execute(char* agrv[])
{
pid_t id = fork();
if(id == 0)
{
execvp(agrv[0],agrv);
exit(1);
}
else
{
int status = 0;
pid_t rid = waitpid(id,&status,0);
if(rid > 0 )
{
lostcode = WEXITSTATUS(status);
}
}
}
void cd(char* argc[])
{
char* path = argc[1];
chdir(path);
getcwd(path,1024);
sprintf(cwd,"PWD=%s",path);
putenv(cwd);
}
int builtin(char* argc[])
{
if(strcmp(argc[0],"cd") == 0)
{
cd(argc);
return 1;
}
else if(strcmp(argc[0],"export") == 0)
{
if(argc[1] == NULL) return 1;
strcpy(env,argc[1]);
putenv(env);
return 1;
}
else if(strcmp(argc[0],"echo") == 0)
{
char* e = argc[1]+1;
if(strcmp(e,"?") == 0)
{
printf("%d\n",lostcode);
return 1;
}
else
{
printf("%s\n",getenv(e));
return 1;
}
}
return 0;
}
int main()
{
while(1)
{
char command[MAXIN];
//获取命令
if(!getcommand(command)) return 1;
//字符串分隔
char* argv[SIZE];
commandsplit(command,argv);
//是否是内建命令
int n = builtin(argv);
if(n) continue;
//指令执行
execute(argv);
}
return 0;
}