一:实验题目
实现一个简单的 shell 命令行解释器
二:实验目的
本实验主要目的在于进一步学会如何在 Linux 系统下使用进程相关的系统调用,了解 shell 工作
的基本原理,自己动手为 Linux 操作系统设计一个命令接口。
三:总体设计(含背景知识或基本原理与算法、或模块介绍、设计步骤等)
要设计的 shell 类似于 sh,bash,csh 等,必须支持以下内部命令:
cd <目录>更改当前的工作目录到另一个<目录>。如果<目录>未指定,输出当前工作目录。如
果<目录>不存在,应当有适当的错误信息提示。这个命令应该也能改变 PWD 的环境变量。
environ 列出所有环境变量字符串的设置(类似于 Linux 系统下的 env 命令)。
echo <内容 > 显示 echo 后的内容且换行
help 简短概要的输出你的 shell 的使用方法和基本功能。
jobs 输出 shell 当前的一系列子进程,必须提供子进程的命名和 PID 号。
quit,exit,bye 退出 shell。
背景知识和基本原理:
Shell 是一种命令行解释器,它提供了用户与操作系统之间的交互界面。Shell 接收用户输入的命令,解释并执行这些命令,然后将结果返回给用户。Shell 在操作系统中起到了承上启下的作用,它可以调用系统的各种功能和服务,同时也是用户与操作系统进行交互的窗口。
设计步骤:
1.读取用户输入的命令行。
2.解析命令行,将命令和参数分离,并进行相应的语法检查。
3.根据解析后的命令,执行相应的操作。这可以是调用系统内置命令,执行外部程序,或者执行一系列其他操作。
4.处理命令执行的结果,并将结果输出给用户。
5.循环执行上述步骤,直到用户选择退出。
具体模块介绍:
输入模块:负责读取用户输入的命令行。
解析模块:负责解析命令行,将命令和参数分离,并进行语法检查。
执行模块:根据解析后的命令,执行相应的操作。这可能涉及调用系统内置命令、执行外部程序等。
输出模块:处理命令执行的结果,并将结果输出给用户。
主控模块:循环执行上述模块,控制整个命令行解释器的流程。
设计步骤:
*设计数据结构,如命令结构体、参数列表等。
*实现输入模块,读取用户输入的命令行。
*实现解析模块,将命令行解析成命令和参数,并进行语法检查。
*实现执行模块,根据解析后的命令执行相应的操作。
*实现输出模块,处理命令执行的结果并将结果输出给用户。
*实现主控模块,循环执行输入、解析、执行和输出模块,控制整个命令行解释器的流程。
*进行测试和调试,确保命令行解释器能够正常运行。
*根据需要进行优化和改进,增加额外的功能或特性。
通过以上步骤,就可以实现一个简单的 shell 命令行解释器。在实际运行中,用户可以输入各种命令,如查看文件、创建目录、执行程序等,解释器将会解析并执行这些命令,并将执行结果返回给用户。
四:详细设计(含主要的数据结构、程序流程图、关键代码等)
主要代码:
char cmd[2100];
while(1)
{
printf("请输入操作:");
scanf("%s",cmd);
int len=strlen(cmd),i;
if(cmd[0] == 'e' && cmd[1] == 'c') // echo
{
int flag=0;
for( i=5; i<len-1; i++)
{
if(cmd[i]!=' ') flag=1;
if(flag)
{
putchar(cmd[i]);
}
}
if(flag) putchar('\n');
}
else if(cmd[0]=='q' || cmd[1]=='x' || cmd[0]=='b') // quit,exit,bye
{
printf("Bye\n");
return 0;
}
else if(cmd[0]=='h') // help
{
printf("/**********************************/\n");
printf("echo <content>\tprint a line content\n");
printf("quit,exit,bye\tend produce\n");
printf("cd <catalog>\techo catalog\n");
printf("jobs\techo process name and pid...\n");
printf("environ\techo environment variable\n");
printf("/**********************************/\n");
}
else
{
char cata[100];
int cnt=0;
if(cmd[0]=='c') // cd
{
int flag=0;
for( i=3; i<len; i++)
{
if(cmd[i]!=' ') flag=1;
if(flag)
{
cata[cnt++] = cmd[i];
}
}
if(cnt==0)
{
cata[0]='.';
cata[1]='\0';
}
}
/* fork a child process */
pid_t pid = fork();
if (pid < 0)
{
/* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if(pid==0)
{
if(cmd[0]=='c') // cd
{
execlp("/bin/ls",cata,NULL);
}
else if(cmd[0]=='j') // jobs
{
execlp("pstree","-p",NULL);
}
else if(cmd[0]=='e') // environ
{
execlp("env","",NULL);
}
}
else
{
/* wait wait,until child process exit*/
wait();}
}
printf("\n");
}
return 0;
五:实验结果与分析
这段代码是一个简单的命令行解释器程序,它接受用户输入的命令并执行相应的操作。以下是对代码进行实验的结果和分析:
程序的主循环使用一个无限循环,可以持续地接收用户输入并处理命令。
当用户输入以"ec"开头的命令时,程序会将除去前面的部分(即"ec"之后的内容)的内容打印出来。这个功能类似于echo命令,可以在屏幕上显示输入的内容。
当用户输入以"q"、"x"或"b"开头的命令时,程序会打印"Bye"并退出。
当用户输入以"h"开头的命令时,程序会打印一系列帮助信息,包括可用命令的说明。
对于其他以字母"c"开头的命令,程序会创建一个子进程来执行相应的操作。具体操作根据命令的不同而有所不同:
如果命令以"cd"开头,则子进程将调用execlp函数来执行/bin/ls命令,以显示指定目录的内容。
如果命令以"j"开头,则子进程将调用execlp函数来执行pstree -p命令,以显示进程树和相关进程的信息。
如果命令以"e"开头,则子进程将调用execlp函数来执行env命令,以显示环境变量的信息。
父进程会等待子进程执行完毕,然后继续下一个循环。
综上所述,这段代码是一个简单的命令行解释器,它具有基本的功能,但也存在一些改进的空间和潜在的问题。实际的实验结果和分析将取决于您在运行代码时输入的具体命令和操作。
六、小结与心得体会
这段代码是一个基本的命令行解释器程序,实现了一些常见的命令操作,如打印内容、退出程序、显示帮助信息、执行系统命令等。
1.代码使用了循环结构,使程序能够持续地接收用户输入并处理命令,增强了交互性。
2.子进程的创建和执行使用了fork和execlp函数,充分利用了操作系统提供的进程管理和执行外部命令的功能。
3.代码中的一些功能存在潜在问题,如输入验证和边界检查不完善,子进程创建和等待的处理方式可以更稳健。这些问题可以通过改进代码来解决,提高程序的健壮性和安全性。
4.在实验过程中,可以尝试不同的命令和参数来测试程序的功能和正确性,观察程序的输出和行为是否符合预期。
5.这段代码为我们提供了一个基本的框架,可以根据需要进一步扩展和改进,添加更多功能和命令,以满足实际需求。