Linux下的Shell程序设计
我们需要设计一个shell程序,目前实现的功能有如下:
- 获取当前操作系统的用户名、当前路径、以及操作权限展示为提示符
- 输入一系列的内部指令并执行:cd、exit、help以及无效指令
- 输入一系列的外部指令并执行:ps、ls执行当前路径文件等
- 利用管道标识符“||”将标识符的命令输出的内容作为标识符后面的命令的输入内容
- 利用 < 和 >进行输入输出的重定向
- 循环执行命令
下面将逐步拆解shell程序讲解其编写
首先我们需要定义我们的shell程序的运行逻辑如下:
1.开启shell程序进程
2.进入执行循环
2.1获取操作系统的用户名、当前路径、操作权限并作为提示符输出
2.2接收一整行的输入
2.3将一整行的输入进行拆解,以空格为分隔符将一整行命令拆解成一个命令数组
2.4分析命令数组,判断是否需要使用管道、重定向
2.5执行命令数组并输出
2.6结束循环
3.程序结束
在决定了我们程序的框架之后就可以进入程序功能的编写了
获取当前操作系统的用户名、当前路径、以及操作权限展示为提示符
Linux的命令行提示符由以下几个部分组成:
操作系统用户名@主机名 相对路径#($)
所以我定义我自己的Shell程序的提示符如下:
操作系统用户名@KlayShell 绝对路径
当为root权限用户是结束符为#
当为普通用户时结束符为$
我们首先需要用geteuid()获取当前的用户id
然后利用用户id作为参数使用getpwuid(uid uid)函数
getpwuid(uid uid)会返回以下的结构体
struct passwd
{
char *pw_name; /* 用户名*/
char *pw_passwd; /* 密码.*/
__uid_t pw_uid; /* 用户ID.*/
__gid_t pw_gid; /*组ID.*/
char *pw_gecos; /*真实名*/
char *pw_dir; /* 主目录.*/
char *pw_shell; /*使用的shell*/
};
这样子我们就可以获取到当前的用户名了
其次我们还需要获取到当前的绝对路径
getcwd()会将当前工作目录的绝对路径复制到参数buffer所指的内存空间中,参数size为buffer的空间大小
其次我们还需要根据之前获取到的用户id选择输出#还是输出$
这部分完整的代码如下:
void print_prompt(){
struct passwd *myinfo;
//获取用户id
int euid= geteuid();
//获取用户信息结构体
myinfo = getpwuid(euid);
//获取主机名(这个舍弃掉了,被置换为我自己定义的名字)
char hostname[80];
gethostname(hostname,sizeof(hostname));
//获取绝对路径
char path[400];
getcwd(path,sizeof(path));
//输出命令提示符
printf("[%s@KlayShell:%s]",myinfo->pw_name,path);
//根据root权限输出
if(euid==0){
printf("# ");
}
else{
printf("$ ");
}
}
得到的结果:
接收一整行的输入并根据空格符进行分割
我们定义两个全局变量,分别用于接收整行输入以及拆分后的输入
//存放输入的命令
char inputCommand[400];
//存放分解后的命令
char command[30][50];
我们直接利用gets(inputCommand)接收一整行的输入
然后利用以下函数根据空格对指令进行切割,并且返回指令的长度
int breakInput2Command(){
char *s = inputCommand;
int i = 0;int j = 0;
while(1){
if((*s)=='\0')