我正在用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检查出的手册页。

NULLchar *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"简单地"必须"调用"类似的程序。 lschdir, ,不执行他们的任务。

ls本身知道,如果没有给出任何参数,它应该在当前工作目录中列出由getcwd 返回的当前工作目录中的文件

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top