在C中编写自己的Unix shell-PATH和execv的问题
题
我正在用C编写自己的shell。它需要能够显示用户当前目录,根据完整路径执行命令(必须使用execv),并允许用户用cd更改目录。
这是家庭作业。老师只给了我们一个关于C的基本入门和一个关于程序应该如何工作的非常简短的骨架。由于我不是一个轻易放弃的人,我一直在研究如何做到这一点三天,但现在我被难住了。
这就是我目前所拥有的:
- 显示用户的用户名、计算机名和当前目录(默认为主目录)。
- 提示用户输入,并获取输入
- 将用户的输入按""分割成一个参数数组
- 将环境变量PATH按":"拆分为令牌数组
我不知道如何从这里开始。我知道我必须使用execv命令,但在我对google的研究中,我还没有真正找到我理解的例子。例如,如果命令是bin/ls,execv如何知道显示主目录中的所有文件/文件夹?如何告诉系统我更改了目录?
我一直在使用这个网站,这对我很有帮助: http://linuxgazette.net/111/ramankutty.html 但再一次,我被难住了。
谢谢你的帮助。让我知道我是否应该发布一些我现有的代码,我不确定是否有必要。
解决方案
要实现cd命令,您只需要系统调用 chdir
.
#include <unistd.h>
int chdir(
const char *path /* the path name */
);
所以你可以这样称呼:
int ret1 = chdir("../foo/bar");
的返回值 chdir
当可以更改到该目录时为0,如果发生错误则为-1。对于错误,您应该合并手册页。
当前目录可以被任何程序检查,所以如果你执行 ls
没有任何参数,然后ls检查它在哪个目录中运行,并使用这个目录作为唯一的参数。这是ls的一个特征,而不是 execv
打电话。
为第二部分。
#include <unistd.h>
int execv(
const char *path, /* programm path*/
char *const argv[]/* argument vector*/
);
execv
在给定的执行可执行文件 path
并与给出的论点 argv
.所以如果你想执行 /bin/ls ../foo /bar
, ,你需要类似于
char *cmd_str = "/bin/ls";
char *argv[] = {cmd_str, "../foo", "/bar", NULL };
if (execv(cmd_str, argv) == -1 ){
/* an error occurred */
}
返回的错误 execv
是-1。如果你想知道为什么它没有执行comand检查出的手册页。
该 NULL
在 char *argv[] = {cmd_str, "../foo", "/bar", NULL };
有没有表明后面没有其他参数 NULL
.
第三部分。基于Unix的系统通常将带有a/的命令视为可以直接执行的命令。这意味着你首先检查给定的命令字符串中是否有斜杠。
int ret_value;
if (strchr(cmd_str, '/')
if (execv(cmd_str, argv) == -1 ){
/* an error occurred */
}
如果没有斜杠,那么你需要通过所有目录 PATH
并检查是否可以执行该命令。所以给定的命令是 ls ../foo /bar
让我们假设 PATH
是 ".:/sbin:/bin:/usr/bin"
.然后,我们将尝试首先执行 ./ls ../foo /bar
然后 /usr/bin/ls ../foo /bar
最后 /bin/ls ../foo /bar
.
希望这有帮助。
其他提示
例如,如果命令是
bin/ls
, ,如何execv
知道从主目录显示所有文件/文件夹?如何告诉系统我更改了目录?
每个进程都有一个当前的工作目录,可以使用 chdir
.子进程将从其父进程继承工作目录。因此,一般来说,您的shell将管理其当前的工作目录以响应 cd
用户输入的命令。当输入一个不是内置的命令时,你将 fork
要创建子进程,然后调用 execv
在那里执行二进制文件。
如果你想把 PATH
考虑到不包含目录部分的程序名称,那么您应该尝试所有可能的组合 PATH
元素和程序名称。您可以检查命名文件是否存在,或者只是尝试执行它并在失败时继续下一个文件。如果有的话 execv
呼叫失败,你将不得不打电话 _exit
以便终止子进程。
请注意,大多数shell将处理包含 /
作为传递给 execv
直接。如果路径没有 开始 用一个 /
, ,那么它是一个相对路径,操作系统将相对于当前工作目录进行解析。换句话说, bin/ls
从你的例子将参考 ls
二进制在 bin
目录是当前工作目录的子目录。只有不包含任何命令的命令 /
在所有要么被解释为一个内置的命令(如 cd
)或位于 PATH
.
第一个论点 execv
是你计算的路径。的第一个元素 argv
列表传统上等于名称,因为它是enetered,即没有添加 PATH
目录。在第一个参数之后,传递任何额外的命令行参数,然后是 NULL
以终止该列表。
我认为问题是,你相信外壳负责做的工作 ls
. ls
不是真正的外壳的"一部分"(至少在这种情况下)。外壳 执行 一个名为 ls
.大多数评论似乎都在解释如何找到 ls
, 但我不相信这就是你所困惑的。
在你写它之前,你应该仔细考虑shell的重点是什么。这些评论间接地指出了一个事实,即shell"简单地"必须"调用"类似的程序。 ls
和 chdir
, ,不执行他们的任务。
ls
本身知道,如果没有给出任何参数,它应该在当前工作目录中列出由getcwd
返回的当前工作目录中的文件