编写简单的shell命令解析器

环境:

RedHat 9.0    内核 2.4.20

vi 文书编辑器  6.1.320

gcc  3.2.2-5

 

实现步骤:

 

第0步:写一个最简单的shell命令解释器,本程序取自APUE例1-5,命令不能带参数。

 

需要完成的内容如下:

  1. 命令解释器首先是一个死循环。
  2. 打印一个命令提示符。
  3. 取得命令行输入放在数组里面,不要求命令带参数。可以getc()、fgets()、scanf()等。
  4. 如果用fgets()的话,取得的字符串包括最后输入的换行符,故要去掉命令字符串末尾的“/n”,变成“/0”。
  5. 创建一个子进程,调用exec执行命令。
  6. 父进程调用waitpid()等待子进程的退出,然后进入下一次循环。

 

第1步:写一个shell命令解释器,使能处理带参数的命令。

 

需要完成的内容如下:

  1. 命令解释器首先是一个死循环。
  2. 打印一个命令提示符,包含当前路径信息。取得命令行输入,本程序是把命令行输入保存在一个字符指针指向的地址中。
  3. 分析命令行,把以空格分开的命令和参数

分别取出来放在字符指针数组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链表的建立没加上判断条件,导致执行后台命令时链表保存重复的内容。