You are on page 1of 3

MyShell 文档

1.MyShell 支持的命令列表及其对应的命令处理函数
命令 处理函数 描述
exit my_exit() 退出 myshell
ls my_ls(char **) 列出当前目录的内容,包括带参和不带参的,
输出重定向
sort my_sort(char **) 对文件中的行进行排序,输入重定向
vi my_vi(char **) 查找文件,后台执行
add my_add(char **) 加法命令,自已实现
args my_args(char **) 数出参数个数,并列出来,自己实现
history my_history(char **) 提供历史机制(只存在于内存中,若 shell
退出重新执行,则所有的历史命令都会不存
在。提供向前 10 条历史命令)
! cmd_no my_ex_history(int) 执行历史命令,没有完成

2.实现思路及一些假设
由于模拟的是 shell,不应该像一般 C 程序那样遇到 SIGINT/SIGQUIT/SIGTSTP 就中
断/退出/挂起,所以对这三种信号都设置其信号处理动作为 SIGIGN。

假设由 getline 读入的字符串数组为 args。


一般情况下,命令都是第一个输入的字符串,接着是命令选项,重定向、后台执行等其
它命令都紧随其后。
对于 myshell 支持的任意一个命令,首先检查该命令到底是哪个,调用相应的命令处理
函数。此处并不考虑重定向、后台处理问题。
对于重定向、后台处理是在每个命令处理函数中单独完成的,没有一个统一调用的接
口。
下面对具体每个支持命令的实现作简单介绍:
exit
处理函数:my_exit(char **)
仅仅是对 exit(int)系统调用的一个简单封装。

ls
处理函数:my_ls(char **)
使用 fork()产生一个子进程,子进程调用 execv()执行系统内置的”ls”命令;父进程调
用 wait()等待子进程,子进程执行完毕,方打印出 myshell 提示符,表示可以继续输入下
一个命令。
ls -l
处理函数:my_ls(char **)
处理过程同上,只不过调用 execv()时增加了一个参数。

ls -l > foo
处理函数:my_ls(char **)
使用 fork()产生子进程后,子进程中调用 freopen()重定向子进程的标准输出,然后再
调用 execv()。

ls -l | more
ls -l | less
处理函数:my_ls(char **)
调用 fork()产生子进程,然后调用 pipe()产生一个管道,子进程再调用 fork()产生孙进
程,子孙进程使用管道连接起来,数据从孙进程流向子进程。孙进程调用 execv()执行”ls
-l”,子进程 wait(),孙进程返回后子进程方开始执行”more”或”less”。子进程执行完毕,
返回到 myshell 界面。

sort
sort < testfile
处理函数:my_sort(char **)
处理过程同”ls -l > foo”;当 sort 后面不带其它选项时,就从标准输入读。

vi &
处理函数:my_vi(char **)
调用 fork()产生子进程,父子进程均调用 setpgid()为子进程建立新的进程组(因为
fork()之后哪个进程先运行无法确定),然后调用 tcsetpgrp()设置前台进程组为父进程组
在的进程组(其实没有必要了,因为子进程所在的进程组默认即是后台进程组)。由于 vi
要从标准输入接收输入,所以会阻塞。使用”ps -ajx”可以看到”/usr/bin/vi”这个进程。
这个进程在 myshell 中是无法结束的,只有当调用 exit 退出时,vi 因为收到 SIGHUP
信号,方会被动关闭。因为 myshell 并不支持作业控制。
当输入命令为”vi”时,使用”ps -ajx”可以看到僵死进程。因为此时 fork()出来的子进程
并不会执行/usr/bin/vi,当它执行完毕时,却没有进程等待获得其结束状态,所以就变为了
僵死进程,最后由 init 来处理。

add 1 2 0xa
处理函数:my_add(char**)
读入 add 后面的参数,判断是 10 进制的还是 16 进制的,然后把字符串转化为数字,
再加起来,返回结果。

args 1 2 3 4 5 “six, seven”


处理函数:my_args(char **)
对 lex.c 进行修改,增加了其对以双引号开始、以双引号结束的参数的识别,所以
getline()返回的值里面”six, seven”就是作为一个参数来对待的。

history
处理函数:my_history(char **)
显示之前键入的 10 个命令,通过字符串数组来实现。如果键入命令已经走过 10 个,则
10 个之前的命令不再被保存。
由于保存命令的 history_cmds 数组仅存在于内存,所以 myshell 重启动后,其历史命
令清零。

! cmd_no
处理函数:my_ex_history(int)
根据 history 命令的显示,选择执行某个历史命令。由于程序结构的问题,这条命令并
未完全实现,仅显示 cmd_no 那一列键入的命令,而不会执行。