为什么我们在`execlp`中双重声明可执行文件名?

时间:2016-12-19 19:08:09

标签: c exec

使用execlp运行命令

execlp("ps", "ps", NULL);

这里可以看到冗余,因为我们两次通过ps。所有exec变体的行为都是一致的。

为什么exec需要这样的冗余?为什么不写,所以我们可以简单地

execlp("ps", NULL);

4 个答案:

答案 0 :(得分:2)

其他答案解释说,您可能会提供与该计划名称不同的argv[0],但尚未解释为什么您可能希望这样做。

某些程序的行为会有所不同,具体取决于用于调用它们的名称。一个常见的例子是贝壳,例如shbashcsh。他们检查argv[0]的第一个字符,如果这是-,则它们作为登录shell而不是常规shell运行。因此,当/bin/login调用用户的登录shell时,它会执行以下操作:

execlp("/bin/bash", "-bash", (char*)NULL);

这样,bash知道它作为登录的一部分运行,并且可以相应地运行。这可以使用选项参数完成,但是那么可能用作登录shell的每个程序都必须识别该选项(一些特殊的用户名具有不是shell的登录shell,而是其他程序,并且需要它们支持与真实shell相同的选项可能会有问题。)

答案 1 :(得分:1)

第一个参数是要执行的文件的路径(/bin/ls/home/development/myproject/foo)。其余参数对应于传递给argv的{​​{1}}向量。想象一下在shell中键入以下内容:

main

可执行路径为$ ./foo bar bletch - 这是传递给./foo的第一个参数。按照惯例,execlp应该是用于调用程序的字符串,因此完整的argv[0]向量是argv。因此,

{"./foo", "bar", "bletch", NULL}

您可能不希望execlp( "./foo", /* executable path */ "./foo", /* argv[0] */ "bar", /* argv[1] */ "bletch", /* argv[2] */ NULL /* argv[3] */ ); 与实际命令路径相同(例如,因为路径是别名或者您不想暴露确切的路径),在这种情况下,您可以使用类似

的内容
argv[0]

答案 2 :(得分:1)

您不必将程序的名称作为argv[0]提供给您的程序。您可以编写一个程序(rvw11.c编译为rvw11可执行文件):

#include <unistd.h>

int main(void)
{
    execlp("sleep", "rip van winkle", "40", (char *)0);
    return 1;
}

你会发现如果你跑:

$ ./rvw11 &
[1] 53034
$ ps
  PID TTY           TIME CMD
  515 ttys000    0:00.07 -bash
  534 ttys002    0:00.09 -bash
  543 ttys003    0:01.15 -bash
  558 ttys004    0:00.32 -bash
53034 ttys004    0:00.01 rip van winkle 40
$

因此,ps列表中显示的名称是参数列表中以argv[0]给出的值,而不是可执行文件的名称。 (在macOS Sierra 10.12.2上进行演示,但在大多数类Unix系统上你会得到类似的结果。)

这也说明了为什么从参数列表中确定可执行文件的名称不一定可行。

答案 3 :(得分:0)

第二个参数与第一个参数匹配,但

根据文件,

  

argv是传递给新程序的参数字符串数组。按照惯例,这些字符串中的第一个应包含与正在执行的文件关联的文件名。

如果您有令人信服的理由从您计划运行的程序中隐藏正在执行的文件的名称,则可以为第二个参数传递所需的任何字符串,包括空或NULL字符串:

execlp("ps", "<hidden>", NULL);