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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15017102/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:24:53  来源:igfitidea点击:

Commands like "ls -l" not executing in execl, whereas in execvp it works

cexec

提问by markfiel

Using the code below in the execlvariant, lsworks, but ls -ldoes not work, but in my execvpapproach lsand ls-lworks. The reason why I adopted the execlapproach is because the path of the binaries could differ whereas execvpdid not provide me that feature. Ideally I want execlto also work on ls -l, but right now it does not work on ls -l. I tried reading the man pages but it did not help.

execl变体中使用下面的代码,ls有效,但ls -l不起作用,但在我的execvp方法lsls-l工作中。我采用这种execl方法的原因是二进制文件的路径可能不同,而execvp没有为我提供该功能。理想情况下,我execl也想继续工作ls -l,但现在它不起作用ls -l。我尝试阅读手册页,但没有帮助。

void child(int argc, char *argv[MAX_ARGS])
{
        execvp(argv[0], argv);
}


void child(char *argv[], char* path)
{
        execl(path, argv, NULL);
}

回答by Jonathan Leffler

With execl(), you have to list the arguments one by one; it is only useful if you know exactly what you're going to execute ahead of time:

使用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);

Etc.

等等。

If you don't know how many arguments you'll have to deal with, use execvp()or one of the other members of the execv*()family. Also note that you have to specify the path of the command; execvp()does a search down $PATH, but execl()does not. Also note that you get to choose the value passed as argv[0].

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

The reason why I adopted the execl()approach is because the path of the binaries could differ whereas execvp()did not provide me that feature.

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

I'm not sure what you mean here. With execvp(), you can specify:

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

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

The execvp()will search for lson $PATHand execute the first program found that matches. The second will execute /bin/lswithout looking at $PATHat all.

execvp()将搜索ls$PATH和执行第一条程序发现匹配。第二个将在/bin/ls不看的情况$PATH下执行。

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

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

Either of these will work; the second won't use a PATH-based search because the executable name (argv[0]) contains a slash.

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



What confuses me is that in execvp(argv[0], argv);why are we passing the entire argvas the 2nd parameter? So suppose argv[0]was "ls -l", why do we have to pass the entire argvas the 2nd parameter?

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

Supposing argv[0]contains "ls -l", you have a problem. Most systems do not have a file "/bin/ls -l" or "/usr/bin/ls -l" (where the blank is part of the name), but that's what you'd be seeking to execute.

假设argv[0]contains "ls -l",你有问题。大多数系统没有文件“ /bin/ls -l”或“ /usr/bin/ls -l”(其中空白是名称的一部分),但这正是您要执行的。

The exec*()functions are the low-level functions for executing processes. The first argument designates the program to be run (normally, a binary; sometimes a script with a shebang line such as #!/bin/shas the first line). In the case of execv()or execvp()or execve()or execvpe(), the second argument is the vector of arguments, just like the main()function receives a vector of arguments (or argument vector, hence argv). This is a null-terminated list of the arguments to the program. If you want to execute the lscommand with the option -l, then you need to specify in the argvthe three(!) values "ls", "-l"and a null pointer:

这些exec*()函数是用于执行进程的低级函数。第一个参数指定要运行的程序(通常是二进制文件;有时是带有 shebang 行的脚本,例如#!/bin/sh第一行)。在execv()orexecvp()execve()or的情况下execvpe(),第二个参数是参数向量,就像main()函数接收参数向量(或参数向量,因此argv)。这是程序参数的以空字符结尾的列表。如果要ls使用 option执行命令-l,则需要argv在三个(!) values 中指定"ls""-l"以及一个空指针:

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

With the execl*()functions, you specify the program to be run as the first argument, and this is then followed by the argument vector written out:

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

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

If you have 10 arguments, you have to write out 10 arguments (plus the null pointer).

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

In the exec*()functions, the names contain:

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

  • l— list format arguments
  • v— vector format arguments
  • p— do PATH lookup on the program (if the given name does not contain a slash)
  • e— take a vector of environment variables too
  • l— 列出格式参数
  • v— 矢量格式参数
  • p— 对程序进行 PATH 查找(如果给定的名称不包含斜杠)
  • e— 也采用环境变量向量

These combine to give:

这些结合起来给出:

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

It is occasionally a tad irksome that there isn't an execlpe()and execvpe()(but see the Linux extension execvpe(3)). It is also traditional for the man 2 execpages to omit some of these from the synopsis but mention them in the body of the manual page — a tradition/legacy dating back to at least 7th Edition UNIX? in 1979 (and perpetuated at least until RHEL 5 Linux and Mac OS X 10.7.5; the man 2 execlpage mentions execve()but does not list it in the Synopsis section). The other exec*()functions can all be built atop execve()— that is the fundamental function in the set (and is listed as execve(2)in the Linux manuals as a result).

偶尔会有点烦人,没有execlpe()execvpe()(但请参阅 Linux 扩展execvpe(3))。这也是传统的man 2 exec网页省略其中的一些从大纲,但他们提到在手册页面的主体-传统/传统可以追溯到至少第7版UNIX?在 1979 年(并且至少持续到 RHEL 5 Linux 和 Mac OS X 10.7.5;该man 2 execl页面提到execve()但没有在概要部分列出它)。其他exec*()函数都可以构建在上面execve()——这是集合中的基本函数(因此execve(2)在 Linux 手册中列出)。