1.实验内容
分析、设计与实现基于 Linux 内核的命令解释程序(Shell),主要包括系统环境变量的设置和初始化、系统命令提示符显示、命令辨别解析(区分内部命令与外部命令及不同内部命令)、典型内部命令(譬如显示指定目录下文件列表、显示文本文件内容、文件拷贝、文件删除、空文件创建、日期设置/显示)处理等功能,并在 Linux 操作系统上测试验证。
2.程序设计思路
- 设计命令列表,这个shell实现了"ls", "cd", "env", "ps", "date", "echo", "help", "exit"八个命令: ls -查看当前目录内容
cd [] -前往指定目录
env -查看环境变量
ps -查看当前进程
date -查看当前的时间
echo [] -显示指定的内容后换行
help -帮助
exit -退出
- shell的输入口实现,设计用户名和获取当前路径
- while循环获取用户输入的命令,在命令列表中则进入对应的命令执行部分,部分通过系统调用实现,命令无效发出报错。
- 对于和终端中一致的命令C++可以直接调用 execlp 系统调用的方式来实现
- 程序使用父子进程来实现并行执行命令和避免阻塞。当用户输入的命令是 "ls"、"env" 、 "ps" 等命令时,父进程会创建一个子进程来执行相应的命令。子进程通过调用 execlp 函数来执行外部命令。程序不会在执行 execlp 函数期间停止等待,这样可以在命令执行期间进行其他操作。
- 设计了一个help列表来展示所有的命令和功能
3.完整程序
cpp
#include <iostream>
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int main() {
vector<string> cmds={"ls", "cd", "env", "ps", "date", "echo", "help", "exit"};
string fp;
while(1) {
string now = "ljj@shell:" + string(getcwd(nullptr, 0)) + "> ";
printf("%s", now.c_str());
string cmd;
cin >> cmd;
string p;
bool valid = false;
int index = -1;
for (int i = 0; i < cmds.size(); i++) {
if (cmd == cmds[i]) {
valid = true;
index = i;
}
}
if (!valid) {
printf("No command! Input -help for more information\n");
continue;
}
else {
if(index < 5) {
// 使用父子进程使得程序可以同时执行多个命令并防止阻塞
pid_t pid;
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) {
if(index == 0) { //ls
execlp("/bin/ls", "ls", NULL);
}
else if(index == 1) { //cd
cin >> p;
chdir(p.c_str());
}
else if(index == 2) { //env
execlp("env", "", NULL);
}
else if(index == 3) { //ps
execlp("ps", "", NULL);
}
else if(index == 4) { //time
execlp("date", "", NULL);
}
}
else {
waitpid(pid, NULL, 0);
}
}
else {
if(index == 5) { //echo
cin >> p;
cout << p << endl;
}
else if(index == 6) { //help
printf("Shell Commands List:\n\
ls -查看当前目录内容\n\
cd [] -前往指定目录\n\
env -查看环境变量\n\
ps -查看当前进程\n\
date -查看当前的时间\n\
echo [] -显示指定的内容后换行\n\
help -帮助\n\
exit -退出\n");
}
else return 0; // exit
}
}
}
return 0;
}