1 简介
用C语言实现的一个简易的shell,能够接受用户输入的命令并执行操作,支持多重管道及重定向。
程序运行后,会模拟shell用绿色字体显示当前的用户名、主机名和路径,等待用户输入命令。程序逐次读取用户输入的指令后,将指令按空格拆分成多个字符串命令,然后判断该命令的类型。若命令有误,则用红色字体打印出错误信息。
- 若命令为exit,则调用自定义的exit函数,向该程序进程发送terminal信号结束该进程。
- 若命令为cd,则判断参数,调用chdir()函数修改当前的路径,并返回相应的结果。若修改成功,则使用getcwd()函数更新当前路径。
- 若为其它命令,则先判断是否有合法的管道。若有管道,则在子进程中执行管道符号前面的命令,父进程等待子进程结束后,递归处理管道符号后面的命令。若没有管道,则直接执行命令。在执行命令的时候,先判断该命令是否存在,以及是否有合法的重定向,再使用execvp()执行相应的操作。
2 功能
- 显示当前用户名、主机名和工作路径
- exit命令
- cd命令
- 判断命令是否存在
- 执行外部命令
- 实现输入、输出重定向
- 递归实现多重管道
3 效果展示
3.1 启动myshell
图中第一行为系统shell,为了与系统区分开,我将自定义的shell的默认信息显示全部设为绿色。由于该路径是个链接,链接到/mnt/g/os_homework/myshell,因此显示出来的路径是实际路径。
3.2 执行cd命令
cd命令的参数可以是相对路径,也可以是绝对路径。当参数出错时,会根据情况用红色字体打印出相应的错误信息。
3.3 执行外部命令
图中演示了“ls -al”、“rm”,以及自定义的可执行程序sum。sum程序要求输入一个整数n,然后求1~n的和。当命令不存在时,返回错误信息。
3.4 重定向
图中展示了输入、输出重定向,程序还会判断重定向是否合法。
3.5 管道
图中展示了多重管道的演示结果,管道与重定向也可以混用。
3.6 exit命令
程序接收到terminal信号后,退出。
4 关键代码
扯了这么多,总得讲一下代码吧。
程序代码已上传到GitHub中~~
4.1 获取用户名、主机名及当前工作路径
void getUsername() { // 获取当前登录的用户名
struct passwd* pwd = getpwuid(getuid());
strcpy(username, pwd->pw_name);
}
void getHostname() { // 获取主机名
gethostname(hostname, BUF_SZ);
}
int getCurWorkDir() { // 获取当前的工作目录
char* result = getcwd(curPath, BUF_SZ);
if (result == NULL)
return ERROR_SYSTEM;
else return RESULT_NORMAL;
}
4.2 以空格分割命令
int splitCommands(char command[BUF_SZ]) { // 以空格分割命令, 返回分割得到的字符串个数
int num = 0;
int i, j;
int len = strlen(command);
for (i=0, j=