【问题标题】:execvp command not running ls -l *.cexecvp 命令未运行 ls -l *.c
【发布时间】:2020-07-15 10:51:17
【问题描述】:

我的execvp 没有运行ls -l *.c 命令。我尝试使用两种方法:

  1. 我的 ls 所在的文件路径位于 \bin\ls 中。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    char *cmdargs[] = { "ls", "-l", "*.c", NULL };
    pid_t pid;
    pid = fork();
    if (pid == 0)
        execvp("\bin\ls", cmdargs);
    else
    {
        wait(NULL);
        printf("Child terminates\n");
    }
    return 0;
}

输出:

ls: *.c: No such file or directory
Child terminates
  1. 我使用的第二种方法是添加cmdargs[0]而不是文件路径。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
    char *cmdargs[] = { "ls", "-l", "*.c", NULL };
    pid_t pid;
    pid = fork();
    if (pid == 0)
        execvp(cmdargs[0], cmdargs);
    else
    {
        wait(NULL);
        printf("Child terminates\n");
    }
    return 0;
}

输出:

ls: *.c: No such file or directory
Child terminates

当我只运行命令ls -l *.c 时,它会显示所有以.c 结尾的文件。 Execvp 没有向我显示文件。有一个与此相关的问题,但这对我没有帮助。

【问题讨论】:

    标签: c unix system system-calls systems-programming


    【解决方案1】:

    GLOB 模式由 shell 扩展,而不是 ls 本身。 你可以通过 exec 创建一个 subshel​​l 来实现你想要的。 这是一个例子:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    int main() {
        char *cmdargs[] = { "sh", "-c", "ls -l *.c", NULL };
    
        pid_t pid;
        pid = fork();
        if (pid == 0) {
            execvp(cmdargs[0], cmdargs);
        } else {
            wait(NULL);
            printf("Child terminates\n");
        }
    
        return 0;
    }
    

    如果你愿意,你也可以为此雇用system(3)

    【讨论】:

      【解决方案2】:

      星号模式* 由shell 继承,但由ls 继承。

      例如,您可以将execsh 一起使用。

      编辑 OP 的回复, 在字符串数组中不使用*.c获取所有文件,并根据需要过滤字符串。

      【讨论】:

      • 这是我的作业问题,它要求我只使用 execvp。
      • @VipulSharma 没有系统调用execexec 是来自man 3 exec 的系统调用execl, execlp, execle, execv, execvp, execvpe - execute a file 家族的名称。所以技术上没有矛盾:)
      【解决方案3】:

      除了调用 shell 将 *.c glob 模式扩展为文件之外,您还可以使用 glob*.c 扩展为自己的文件列表,然后构造一个动态分配的参数数组。

      #include <stdio.h>
      #include <unistd.h>
      #include <sys/types.h>
      #include <sys/wait.h>
      #include <glob.h>
      #include <stdlib.h>
      
      int main() {
          glob_t result = {0};
          int err = glob("*.c", GLOB_ERR, NULL, &result);
          if (err) return err;
          char **cmdargs = malloc((2 + result.gl_pathc + 1) * sizeof(cmdargs));
          if (cmdargs == NULL) return EXIT_FAILURE;
          cmdargs[0] = "ls";
          cmdargs[1] = "-l";
          for (size_t i = 0; i < result.gl_pathc; ++i) {
              cmdargs[i + 2] = result.gl_pathv[i];
          }
          cmdargs[2 + result.gl_pathc] = NULL;
      
          pid_t pid = fork();
          if (pid == 0) {
              execvp(cmdargs[0], cmdargs);
          } else {
              wait(NULL);
              printf("Child terminates\n");
          }
          globfree(&result);
          return 0;
      }
      

      【讨论】:

        【解决方案4】:

        当您输入ls -l *.c 时,shell 将解析该命令,找到 glob 模式并将其展开。然后它将使用扩展的参数列表调用ls,使用类似{"ls", "-l", "a.c", "b.c", "c.c", NULL} 的数组调用execvplsexecvp 都不会自行扩展 glob,而是由 shell 完成。

        因此,如果您想使用 glob,您可以选择自己扩展它们(通过手动浏览当前目录并将所有以 .c 结尾的文件添加到您的数组中,或者使用 POSIX glob 函数),或通过外壳。您可以通过使用{"sh", "-c", "ls -l *.c", NULL} 作为您传递给execvp 的数组来显式调用后者(或者类似地,但没有数组,使用execl 等),或者您可以使用system("ls -l *.c"),这总是通过外壳。

        请注意,如果参数包含不受信任的用户输入,您绝对不想通过 shell,因此在这种情况下,您可以自己扩展 glob/使用glob

        【讨论】:

          猜你喜欢
          • 2012-12-27
          • 1970-01-01
          • 2023-03-21
          • 2011-01-15
          • 1970-01-01
          • 1970-01-01
          • 2014-03-20
          • 2012-04-10
          • 1970-01-01
          相关资源
          最近更新 更多