在C中编写自己的Unix shell - PATH和execv的问题

时间:2012-09-29 05:03:36

标签: c shell unix execv getenv

我在C中编写自己的shell。它需要能够显示用户当前目录,根据完整路径执行命令(必须使用execv ),并允许用户用cd更改目录。

这是作业。老师只给了我们关于C的基础入门,以及关于程序应该如何工作的非常简短的框​​架。因为我不是一个容易放弃的人,所以我一直在研究如何做这三天,但现在我很难过。

这是我到目前为止所做的:

  • 显示用户的用户名,计算机名和当前目录(默认为主目录)。
  • 提示用户输入,并获取输入
  • 将用户的输入按“”拆分为参数数组
  • 通过“:”将环境变量PATH拆分为一个标记数组

我不确定如何从这里开始。我知道我必须使用execv命令,但在谷歌的研究中,我还没有找到一个我理解的例子。例如,如果命令是bin / ls,execv如何知道显示主目录中的所有文件/文件夹?如何告诉系统我更改了目录?

我一直在使用这个网站很多很有帮助:http://linuxgazette.net/111/ramankutty.html但是又一次,我很难过。

感谢您的帮助。如果我发布一些现有代码,请告诉我,但我不确定是否有必要。

4 个答案:

答案 0 :(得分:1)

  

例如,如果命令是bin/lsexecv如何知道显示主目录中的所有文件/文件夹?如何告诉系统我更改了目录?

每个进程都有一个当前工作目录,可以使用chdir进行修改。子进程将从其父进程继承工作目录。因此,通常,您的shell将管理其当前工作目录以响应用户输入的cd命令。当输入的命令不是内置命令时,您将fork创建一个子进程,然后在那里调用execv来执行二进制文件。

如果您考虑将PATH考虑到不包含目录部分的程序名,那么您应该尝试PATH元素和程序名称的所有可能组合。您可以检查指定的文件是否存在,或者只是尝试执行它,如果失败则继续执行下一个文件。如果所有execv次呼叫都失败,则必须致电_exit才能终止子进程。

请注意,大多数shell会将包含/的任何命令视为直接传递给execv的路径。如果路径 <{1}},则它是相对路径,操作系统将根据当前工作目录解析它。换句话说,示例中的/将引用bin/ls目录中的ls二进制文件,该目录是当前工作目录的子目录。只有完全不包含bin的命令才会被解释为内置命令(如/)或cd上的某个二进制文件的名称。

PATH的第一个参数是计算它时的路径。 execv列表的第一个元素传统上等于它被占用的名称,即没有添加argv目录。在第一个参数之后,传递任何其他命令行参数,然后传递PATH以终止列表。

答案 1 :(得分:1)

要实现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。如果你想知道它为什么没有执行命令,请查看手册页。

NULL中的char *argv[] = {cmd_str, "../foo", "/bar", NULL };表示NULL之后没有其他参数。

第三部分。 基于Unix的系统通常将带有/的命令视为可以直接执行的命令。这意味着您首先检查给定命令字符串中是否存在斜杠。

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

希望这有帮助。

答案 2 :(得分:1)

我认为问题是你认为shell负责ls的工作。 ls并不是shell的“部分”(至少在这种情况下)。 shell 执行一个名为ls的程序。大多数评论似乎都在解释如何找到ls,但我不相信这是你感到困惑的。

在编写shell之前,您应该仔细考虑shell的重点。这些评论间接指出了这样一个事实:shell“只是”必须“调用”lschdir之类的程序,而不是执行他们的任务。

答案 3 :(得分:1)

ls自己知道,如果没有给出任何参数,它应该列出getcwd

返回的当前工作目录中的文件