像“ls -l”这样的命令不在execl中执行,而在execvp中它可以工作

时间:2013-02-22 04:53:14

标签: c exec

使用execl变体中的以下代码,ls有效,但ls -l不起作用,但在execvp方法ls和{{{ 1}}有效。我采用ls-l方法的原因是因为二进制文件的路径可能不同,而execl没有为我提供该功能。理想情况下,我希望execvp也适用于execl,但现在它不适用于ls -l。我尝试阅读手册页,但没有帮助。

ls -l

1 个答案:

答案 0 :(得分:11)

使用execl(),您必须逐个列出参数;它只有在你确切知道你将要提前执行的内容时才有用:

execl("/bin/ls", "ls", "-l", (char *)0);
execl("/bin/sh", "sh", "-c", "ls -l", (char *)0);
execl("/bin/ls", "pink elephants", "-l", (char *)0);

如果您不知道有多少参数需要处理,请使用execvp()execv*()系列的其他成员之一。另请注意,您必须指定命令的路径; execvp()向下搜索$PATH,但execl()没有。 另请注意,您可以选择传递的值argv[0]

  

我采用execl()方法的原因是因为二进制文件的路径可能不同,而execvp()没有为我提供该功能。

我不确定你的意思。使用execvp(),您可以指定:

char *argv[] = { "ls", "-l", 0 };
execvp(argv[0], argv);
execv("/bin/ls", argv);

execvp()将在ls上搜索$PATH并执行匹配的第一个程序。第二个将执行/bin/ls而不会查看$PATH

char *argv[] = { "/bin/ls", "-l", 0 };

execv(argv[0], argv);
execvp(argv[0], argv);

其中任何一个都可行;第二个将不使用基于PATH的搜索,因为可执行文件名称(argv[0])包含斜杠。


  

让我感到困惑的是,execvp(argv[0], argv);为什么我们将整个argv作为第二个参数传递?因此,假设argv[0]"ls -l",为什么我们必须将整个argv作为第二个参数传递?

假设argv[0]包含"ls -l",则表示您遇到了问题。大多数系统没有文件“/bin/ls -l”或“/usr/bin/ls -l”(其中空白是名称的一部分),但这就是您要执行的内容。

exec*()函数是执行进程的低级函数。第一个参数指定要运行的程序(通常是二进制;有时是一个带有shebang行的脚本,例如#!/bin/sh作为第一行)。对于execv()execvp()execve()execvpe(),第二个参数是参数的向量,就像main()函数接收向量的向量一样参数(或参数向量,因此argv)。这是程序参数的以null结尾的列表。如果要使用选项ls执行-l命令,则需要在argv中指定三个(!)值"ls""-l"和一个空指针:

char argv[] = { "ls", "-l", 0 };

使用execl*()函数,指定要作为第一个参数运行的程序,然后写出参数向量:

execl("/bin/ls", "ls", "-l", (char *)0);

如果你有10个参数,你必须写出10个参数(加上空指针)。

exec*()函数中,名称包含:

  • l - 列表格式参数
  • v - 矢量格式参数
  • p - 对程序执行PATH查找(如果给定名称不包含斜杠)
  • e - 采用环境变量向量

这些结合起来给出:

  • execl()
  • execv()
  • execlp()
  • execle()
  • execvp()
  • execve()

有时令人厌烦的是,没有execlpe()execvpe()(但请参阅Linux扩展程序execvpe(3))。对于man 2 exec页面来说,从概要中省略其中的一些内容也是传统的,但在手册页的正文中提到它们 - 传统/遗产可以追溯到1979年至少第7版UNIX™(并且延续至至少直到RHEL 5 Linux和Mac OS X 10.7.5; man 2 execl页面提到execve()但未在概要部分列出它。其他exec*()函数都可以在execve()之上构建 - 这是集合中的基本函数(因此在Linux手册中列为execve(2))。