Professional Documents
Culture Documents
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。
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 进制的,然后把字符串转化为数字,
再加起来,返回结果。
history
处理函数:my_history(char **)
显示之前键入的 10 个命令,通过字符串数组来实现。如果键入命令已经走过 10 个,则
10 个之前的命令不再被保存。
由于保存命令的 history_cmds 数组仅存在于内存,所以 myshell 重启动后,其历史命
令清零。
! cmd_no
处理函数:my_ex_history(int)
根据 history 命令的显示,选择执行某个历史命令。由于程序结构的问题,这条命令并
未完全实现,仅显示 cmd_no 那一列键入的命令,而不会执行。