1

我正在尝试编写一个基本的 shell,它可以用 c 语言解释简单的命令,如日期、ls。

我首先获取这样的 PATH 变量,然后将其传递给 execv() 函数。

const char *name = "PATH";
char *value;
value = getenv(name)

我打印出这个值,我得到了这个:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

请注意,我正在使用virutalbox 来运行Ubuntu。这是我用来尝试简单 ls 命令的代码。在下面的代码中,变量行是用户编写的实际命令,在我们的例子中是“ls”

  pid_t pid, wpid;
  int status;

  pid = fork();
  if (pid == 0) {
      // Child process
      if (execv(value, line) == -1) {
          perror("lsh");
      }
      exit(EXIT_FAILURE);
  }
  else if (pid < 0) {
        // Error forking
        perror("lsh");
  }
  else {
      // Parent process
      do {
          wpid = waitpid(pid, &status, WUNTRACED);
      }
      while (!WIFEXITED(status) && !WIFSIGNALED(status));
    }

我得到的结果是这样的:

lsh: no such file or directory

有任何想法吗?

4

2 回答 2

5

系统调用使用您在第一个参数中指定的execv()名称作为可执行文件的文件名;它不进行基于路径的搜索。

这意味着如果您指定"lsh"为第一个参数,则当前目录中必须有一个可执行文件lsh

如果您想要基于 PATH 的搜索,请替换execv()execvp(). 否则,在第一个参数中指定命令的路径名(绝对或相对,但绝对更正常)。

请注意,如果任何exec*()函数返回,则它已失败。无需测试返回值;它永远是-1。

内容valueline需要符合以下内容:

char *value = "ls";
char *line[] = { "ls", "-l", 0 };

execvp(value, line);

或者,更传统地说:

execvp(line[0], line);

如果您自己分析 PATH,则需要line[0]指向从 PATH 创建的完整文件名,然后execv()使用execvp().

于 2015-11-19T20:42:29.870 回答
0

第一个参数execv是要运行的命令。这意味着您正在尝试/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games作为命令运行。

假设line数组中的第一个值是您要调用的程序,您应该这样做:

execv(line[0], line);

如果要执行基于路径的搜索,请execvp改用(无需手动提取 PATH 变量):

execvp(line[0], line);

编辑:

例如,假设您想运行ls -l /usr/bin /var/log,您的数组将如下所示:

char *line[] = { "ls", "-l", "/usr/bin", "/var/log", NULL};
于 2015-11-19T20:46:25.780 回答