编写简单的shell命令解析器
环境:
RedHat 9.0 内核 2.4.20
vi 文书编辑器 6.1.320
gcc 3.2.2-5
实现步骤:
第0步:写一个最简单的shell命令解释器,本程序取自APUE例1-5,命令不能带参数。
需要完成的内容如下:
- 命令解释器首先是一个死循环。
- 打印一个命令提示符。
- 取得命令行输入放在数组里面,不要求命令带参数。可以getc()、fgets()、scanf()等。
- 如果用fgets()的话,取得的字符串包括最后输入的换行符,故要去掉命令字符串末尾的“/n”,变成“/0”。
- 创建一个子进程,调用exec执行命令。
- 父进程调用waitpid()等待子进程的退出,然后进入下一次循环。
第1步:写一个shell命令解释器,使能处理带参数的命令。
需要完成的内容如下:
- 命令解释器首先是一个死循环。
- 打印一个命令提示符,包含当前路径信息。取得命令行输入,本程序是把命令行输入保存在一个字符指针指向的地址中。
- 分析命令行,把以空格分开的命令和参数
分别取出来放在字符指针数组arg[]中。这里取得的命令行字符串保存在input指向的地址。为了把这一行字符串中的命令和参数分开,需要一个临时数组tmp(本程序是重用前面使用的buf数组),把input指向命令行中的命令和参数分别保存在arg[0]、arg[1]等等。
exec执行命令。
shell命令解释器)根据命令是在前台还是后台运行,决定是否调用waitpid()。然后进入下一次循环。
第2步:加入内部命令cd、exit。
需要完成的内容如下:
1步为基础,在分析完命令行输入后,看输入的命令arg[0]是不是“exit”或者“cd”,如果是的话,在执行创建子进程去执行这个命令之前就做为内部命令执行。
exit命令的实现只要打印一句话“Bye bye!”,然后释放前面分配的内存空间,然后退出即可。
3.cd命令的实现用到函数chdir(arg[1]),它用来改变当前工作目录。
第3步:程序的实现分别放在几个文件中,引入头文件的概念。引入重定向和管道函数,但不用具体实现这两个函数。
需要完成的内容如下:
1.引入头文件,把公共的变量和函数放在头文件中,注意防止头文件被重复包含。
redirect()和my_pipe()处理重定向和管道,这两个函数的实现放在一个单独的文件中,不用具体实现这两个函数。
第4步:引入环境变量配置文件mysh_profile,读取环境变量,判断文件是否存在,若存在,执行命令,否则打印“command not found”。
需要完成的内容如下:
PATH环境变量如下:PATH=/bin:/sbin:/usr/bin:/usr/sbin
2.创建函数init_environ(),读取环境变量到数组。
is_founded(),查找文件,看文件是否存在。
第5步:实现重定向功能。
需要完成的内容如下:
redirect.c文件中实现redirect()函数。
第6步:实现管道功能
需要完成的内容如下:
pipe.c文件中实现my_pipe()函数。
第7步:实现历史记录命令history
需要完成的内容如下:
mysh.h中增加表示历史记录的循环数组的数据类型,并定义相应变量。
history.c中实现函数add_history()和history_cmd()。
main.c中,分别在管道、重定向、内部命令、普通命令执行前,把命令行内容加入到命令历史记录循环数组中。
第8步:实现后台作业队列,加入内部命令jobs、bg、fg命令。
测试完成的功能:
第0步骤:
1. 要求每个命令完成后,重新打印出提示符
2. 测试:ls cat 等命令
第1步骤:参数
1. 提示符中出现当前路径信息。
2. 测试命令“ls”,“ls<空格>”,“<空格>ls”,“<空格>ls<空格>”
“ls -a -l” ,“<空格>ls <多个空格> -a <多个空格>-l”
第2步骤:cd exit
1. 测试"cd ..", "cd /home" , "cd -" , "cd~" 等命令
第4步骤:环境变量
1. 把/bin/ls文件拷贝到/home目录,
并将/bin/ls重命名为/bin/ls-bk,测试ls命令
2.在环境变量文件mysh_profile中添加"/home"目录,测试ls命令
第5步骤:重定向
1. 测试 "ls>test" , "ls(空格)>(空格)test" , "ls(空格)>test"命令
2. 测试 "ls>>test" , "ls(空格)>>(空格)test" , "ls(空格)>>test"命令
3. 测试"cat<test" , "cat(空格)<(空格)test", "cat(空格)<test"命令
4. 测试"cat>test<test1", "cat>test1<test"命令。test由 "ls -al >> test"生成
第6步骤:管道
1. 测试"ls(空格)|(空格)more"命令
第7步骤:历史记录
1. 测试用上下键从历史记录中提取命令
第8步骤:作业管理
1. 测试jobs, bg , fg, "Ctrl+c","Ctrl+z" 命令
总结:这个项目主要涉及到的知识:进程控制、进程通信。当然,c语言的基础是最重要的。
项目的基本功能已实现,但存在一些待解决问题:1.历史命令调出,对之进行增减后还不能执行相应的命令;2.jobs链表的建立没加上判断条件,导致执行后台命令时链表保存重复的内容。