【问题标题】:execvp() ls no such file or directoryexecvp() ls 没有这样的文件或目录
【发布时间】:2017-02-10 15:28:37
【问题描述】:

我正在编写一个 shell 模拟器,如果用户键入“lsh ls”,我将运行命令ls 并忽略用户输入的“lsh”。所以我使用 readline 库来获取输入,然后解析该行。然后我使用 fork() 和 execvp() 来运行 ls 命令。但是,当我输入 lsh ls 时,我得到以下输出:

lsh: ls: No such file or directory

这是我的代码。我认为它将 ls 视为要搜索的文件,但我不明白它为什么这样做。

int main(){
  pid_t id;
  char* line;
  char **args;
  while(1){
    line = readline("shell: > ");
    if(strcmp(line,"exit") == 0){
        break;
    }
    args = parse(line);
    if(strcmp(args[0],"lsh") == 0){
        id = fork();
        if (id == 0){
            if(execvp(args[1],args) < 0){
                perro("no such command");
            }
        }
        if(id > 0){
            printf("I am the parent process, id %d\n",getppid());
        }
    }   
    free(line);
  }
}

这是解析行的函数。

#define LSH_TOK_BUFSIZE 64
#define LSH_TOK_DELIM " \t\r\n\a"
char **parse(char *line){
   int bufsize = LSH_TOK_BUFSIZE, position = 0;
   char **tokens = malloc(bufsize * sizeof(char*));
   char *token;
   if (!tokens) {
    fprintf(stderr, "lsh: allocation error\n");
        exit(EXIT_FAILURE);
   }

  token = strtok(line, " \n");
  while (token != NULL) {
    tokens[position] = token;
    position++;

  if (position >= bufsize) {
    bufsize += LSH_TOK_BUFSIZE;
    tokens = realloc(tokens, bufsize * sizeof(char*));
  if (!tokens) {
    fprintf(stderr, "lsh: allocation error\n");
    exit(EXIT_FAILURE);
  }
  }

  token = strtok(NULL, LSH_TOK_DELIM);
  }
  tokens[position] = NULL;
  return tokens;
  free(tokens);
}

【问题讨论】:

  • 通过 strace -f 运行可执行文件以检查它究竟试图生成什么。 execvp 很可能应该是 execvp(args[1], args+1)。
  • 在调用`exec之前添加一些调试代码打印出所有args的元素指向怎么样?
  • 我得到 args[0] = lsh, args[1] = ls, args[2] = null
  • @penatozawa 您的目标是完全跳过 args[0],这就是 args[1] 和 args+1 的原因。下面的答案解释了到底发生了什么; &args[1] 与 (args + 1) 相同。
  • 谢谢你们。这解决了它。

标签: c shell ls


【解决方案1】:

您看到的错误消息来自ls,而不是lsh

实际上你有:

char *args[] = { "lsh", "ls", 0 };

execvp(args[1], args);

这意味着您尝试执行ls,并且执行成功,但您告诉ls,它被称为lsh,因为argv[0] 设置为lsh,并请求它列出文件@ 987654329@ 在当前目录中。因此,当ls 尝试查找文件时,它会失败,并使用您给它的命令名称lsh 报告错误。

你可以试试这个(显示的输出是在 macOS Sierra 上获得的):

$ cp /bin/ls xx97
$ ./xx97 23-ish
xx97: 23-ish: No such file or directory
$ rm xx97

你需要使用:

execvp(argv[1], &argv[1]);

然后你将以正统的方式调用ls

【讨论】:

    猜你喜欢
    • 2013-03-31
    • 2019-03-31
    • 2016-02-16
    • 1970-01-01
    • 2019-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多