在《写一个自己的Unix Shell(2)将读入的字符变成命令》这篇文章中,我们实现了将输入的字符转成命令的功能。例如当我们输入ls
时,我们的Shell程序会开辟一个子进程,将ls
字符串转成字符串数组,然后调用execvp()
函数去环境变量PATH中的目录中查找ls
对应的可执行文件并执行它。对于其他常见的命令也是这个过程,但有两个命令除外,那就是cd
命令和exit
命令。我们知道:cd
命令的作用是切换目录,exit
命令是退出Shell程序。
对于cd
命令来说,它切换的是Shell程序的工作目录,什么是工作目录?工作目录就是你现在在操作系统的哪个目录下,比如你在/root/
目录下,那么/root/
就是Shell进程的工作目录,你在/home/hello/
目录下,/home/hello/
就是Shell进程的工作目录,切换Shell进程的工作目录需要Shell程序的父进程来完成,因为如果是子进程切换工作目录切换的是子进程的,它不会影响到父进程的工作目录。当然,子进程可以继承父进程的工作目录,就是说假设父进程的工作目录是/root/
,那么当父进程fork()
出子进程后,子进程这时的工作目录也是/root/
,但子进程之后再切换工作目录,这就与父进程无关了。
对于exit
命令来说,它是退出Shell进程,那么它必须由Shell程序的父进程执行,因为是父进程在不断的等待输入,解析,开辟子进程执行命令,所以我们要实现在父进程中检测用户输入的是否是exit
命令,如果是,那么就退出Shell程序。
综上,我们要在Shell程序的父进程中实现切换工作目录和退出Shell程序的功能。
我们用chdir()
系统调用来实现切换进程当前工作目录的功能。下面看看chdir()
函数的声明。
1 | int chdir(const char *pathname); |
chdir()
系统调用的函数声明非常简单,它接受一个绝对路径或相对路径来设置工作目录,成功返回0,失败返回-1。
我们用handleChangeDirCommand()
函数来实现解析cd
命令并切换工作目录的功能,下面是handleChangeDirCommand()
函数的实现。
1 | /* |
在handleChangeDirCommand()
函数的实现中,我们复用了parseCmdString()
函数将命令字符串转成字符串数组方便我们后面判断。然后我们检查是否输入了cd
命令,如果输入了cd
命令并且cd
命令的后面没有目标路径的话,我们切换到当前用户的家目录(用getenv("HOME")
来获取当前用户的家目录,getenv()
用来获取指定的环境变量的值,HOME是一个环境变量,就像PATH一样,只不过HOME环境变量存放的是当前用户家目录的字符串)。如果输入了cd
命令,并且cd
命令的后面存在一个目标路径的话,那我们就会使用chdir()
函数将当前工作目录切换到目标目录。如果没有输入cd
命令,就返回0。
我们用handleExitCommand()
函数来实现对退出程序命令的处理,它的实现如下。
1 | /* |
首先我们将cmdString转成字符串数组,然后判断它是不是exit
命令,如果是直接退出,否则返回0。
现在我们有了对切换工作目录功能和退出程序功能的处理,接下来我们将这两个功能集成到我们上一篇文章《写一个自己的Unix Shell(2)将读入的字符变成命令》的程序中。我们只需在execCommand()
函数中调用handleChangeDirCommand()
函数和handleExitCommand()
函数即可。代码如下。
1 | /* |
如果是cd
命令或exit
命令我们就不再往下执行,直接返回(当然,如果是exit
命令程序就直接结束了)。
下图是程序执行的样子。
现在我们可以切换当前工作目录和退出程序了。
附:
欢迎大家关注我的微信公众号^_^。
