C语言 execvp 如何运行命令?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14301407/
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
How does execvp run a command?
提问by as3rdaccount
I know execvpcan be used to execute simple commands as follows:
我知道execvp可以用来执行简单的命令如下:
char* arg[] = {"ls", "-l", NULL};
execvp(arg[0],arg);
I want to know what goes on in here when I run execvp. In man page it says execvpreplaces the image of the process image with the new one. However here I am running a command not an executable.
我想知道我跑步时这里发生了什么execvp。在手册页中,它说execvp用新的图像替换过程图像的图像。但是在这里我运行的是命令而不是可执行文件。
To be specific, say there is a command that specifically requires an input e.g. cat. If I have a text file text.txt which contains the file name expected for cat and I redirect stdin to the file stream of the file, would the output of execle("cat","cat",NULL)or execvp("cat", arg)(obviously where arg stores "cat"and NULL) result in the output in the console as the cat /filenamewould? My intuition is I have to read the file and may be parse it to store the arguments in the arg. However I want to make sure.
具体来说,假设有一个命令特别需要输入,例如 cat。如果我有一个包含 cat 预期文件名的文本文件 text.txt 并且我将 stdin 重定向到文件的文件流,execle("cat","cat",NULL)or execvp("cat", arg)(显然是 arg 存储"cat"和NULL)的输出会导致控制台中的输出作为cat /filename将?我的直觉是我必须读取文件,并且可能会解析它以将参数存储在 arg 中。不过我想确定一下。
Thanks in advance!
提前致谢!
采纳答案by Michael Foukarakis
Here's what happens in an execvpcall:
以下是execvp通话中发生的事情:
- Your libc implementation searches in
PATH, if applicable, for the file that is to be executed. Most, if not all, commands in UNIX-like systems are executables. What will happen if it is not? Try it. Have a look at how glibc does it. - Typically, if the executable is found, a call to
execvewill be made. Parts ofexecvemay be implemented in libc or it may be a system call (like in Linux). - Linux prepares a program by allocating memory for it, opening it, scheduling it for execution, initialises memory structures, sets up its arguments and environment from the supplied arguments to the
execvpcall, finds a handler appropriate for loading the binary, and sets the current task (theexecvpcaller) as not executing. You can find its implementation here.
- 您的 libc 实现在 中搜索
PATH要执行的文件(如果适用)。大多数(如果不是全部)类 UNIX 系统中的命令都是可执行文件。如果不是,会发生什么?尝试一下。看看glibc 是如何做到的。 - 通常,如果找到可执行文件,则会调用
execve。部分execve可能在 libc 中实现,也可能是一个系统调用(如在 Linux 中)。 - Linux 通过为程序分配内存、打开它、调度执行、初始化内存结构、从提供的参数到
execvp调用设置其参数和环境、找到适合加载二进制文件的处理程序以及设置当前任务来准备程序(execvp调用者)作为未执行。你可以在这里找到它的实现。
All steps above conform to the requirements set by POSIX which are described in the relevant manual pages.
以上所有步骤都符合 POSIX 设置的要求,这些要求在相关手册页中进行了描述。
回答by SaveTheRbtz
Regarding your questions:
关于您的问题:
In man page it says
execvpreplaces the image of the process image with the new one. However here I am running a command not an executable.
在手册页中,它说
execvp用新的图像替换过程图像的图像。但是在这里我运行的是命令而不是可执行文件。
Long-long time ago shell was very limited and almost all UNIX commands was standalone executables. Now, mostly for speed purposes some subset of UNIX commands is implemented inside shell itself, those commands are called builtins. You can check whatever command is implemented in your shell as built-in or not via typecommand:
很久以前,shell 非常有限,几乎所有 UNIX 命令都是独立的可执行文件。现在,主要是为了提高速度,一些 UNIX 命令的子集是在 shell 本身内部实现的,这些命令被称为builtins. 您可以通过以下type命令检查在您的 shell 中实现的任何命令是否为内置命令:
λ ~/ type echo
echo is a shell builtin
(Full list of builtins with descriptions can be found in manpages to your shell e.g. man bash-builtinsor man builtin.)
(带有描述的完整内置函数列表可以在man你的 shell 页面中找到,例如man bash-builtins或man builtin。)
But still most of the commands still have their executable-counterpart:
但是大多数命令仍然有它们的可执行对应部分:
λ ~/ whereis echo
/bin/echo
So in your specific case when you are running:
因此,在您运行时的特定情况下:
char* arg[] = {"ls", "-l", NULL};
execvp(arg[0],arg);
You are actually replacing address space of current process with address space of (most likely) /bin/ls.
您实际上是用 (最有可能) 的地址空间替换当前进程的地址空间/bin/ls。
My intuition is I have to read the file and may be parse it to store the arguments in the arg.
我的直觉是我必须读取文件,并且可能会解析它以将参数存储在 arg 中。
Indeed you you have. But you also may use some in-kernel functions for that aka "shebang":
Instead of putting file name in separate file add so-called shebang as the first line of the file you want to cat:
你确实有。但是您也可以使用一些内核函数来实现,也就是“shebang”:
不要将文件名放在单独的文件中,而是将所谓的 shebang 添加为您想要 cat 的文件的第一行:
#!/bin/cat
And add chmod +xto it. Then you can run it as executable (via any of execfunctions or shell):
并添加chmod +x它。然后您可以将其作为可执行文件运行(通过任何exec函数或 shell):
λ ~/tmp/ printf '#!/bin/cat\nTEST\n' > cat_me
λ ~/tmp/ chmod +x cat_me
λ ~/tmp/ ./cat_me
#!/bin/cat
TEST
Of cause it's has a drawback of printing shebangitself with file but still it's fun to do it in-kernel =)
当然,它有一个缺点,shebang就是用文件打印自己,但在内核中进行打印仍然很有趣 =)
BTW. Problem that you described if so common that there is a special executable called xargswhich (in very simplified explanation) executes given program on list of arguments passed via stdin. For more information consult with man xargs.
顺便提一句。您描述的问题是否如此普遍以至于有一个特殊的可执行文件被调用xargs(以非常简化的解释)在通过标准输入传递的参数列表上执行给定的程序。有关更多信息,请咨询man xargs。
For easy memorization of exec-family I often use following table:
为了便于记忆exec-family 我经常使用下表:
Figure 8.14. Differences among the six exec functions
+----------+----------+----------+----------+--------+---------+--------+
| Function | pathname | filename | agr list | argv[] | environ | envp[] |
+----------+----------+----------+----------+--------+---------+--------+
| execl | * | | * | | * | |
+----------+----------+----------+----------+--------+---------+--------+
| execlp | | * | * | | * | |
+----------+----------+----------+----------+--------+---------+--------+
| execle | * | | * | | | * |
+----------+----------+----------+----------+--------+---------+--------+
| execv | * | | | * | * | |
+----------+----------+----------+----------+--------+---------+--------+
| execvp | | * | | * | * | |
+----------+----------+----------+----------+--------+---------+--------+
| execve | * | | | * | | * |
+----------+----------+----------+----------+--------+---------+--------+
| letter | | p | l | v | | e |
+----------+----------+----------+----------+--------+---------+--------+
So in your case execvptakes filename, argv(v) and environ(e).
Then it's tries to "guess" pathname (aka full path) by appending filename(in your case cat) to each path component in PATHuntil it find path with executable filename.
所以在你的情况下execvp需要文件名,argv( v) 和environ( e)。然后它尝试通过将filename(在您的情况下cat)附加到每个路径组件来“猜测”路径名(又名完整路径),PATH直到它找到具有可执行文件的路径filename。
Much more information about whats going on under the exec's hood (including inheritance stuff) can be found in Advanced Programming in the UNIX Environment (2nd Edition) by W. Richard Stevens and Stephen A. Ragoaka APUE2.
If you are interested in UNIX internals you should probably read it.
exec可以在W. Richard Stevens 和 Stephen A. Ragoaka APUE2的 UNIX 环境中的高级编程(第 2 版)中找到更多关于幕后发生的事情(包括继承的东西)的信息。
如果您对 UNIX 内部结构感兴趣,您可能应该阅读它。
回答by Verdagon
"ls" isn't just a command, it's actually a program (most commands are). When you run execvp like that, it will nuke your entire program, its memory, its stack, its heap, etc... conceptually "clear it out" and give it to "ls" so it can use it for its own stack, heap, etc.
“ls”不仅仅是一个命令,它实际上是一个程序(大多数命令都是)。当你像这样运行 execvp 时,它会毁掉你的整个程序、它的内存、它的堆栈、它的堆等等......概念上“清除它”并将其交给“ls”,以便它可以将它用于自己的堆栈,堆等
In short, execvp will destroy your program, and replace it with another program, in this case "ls".
简而言之,execvp 将破坏您的程序,并用另一个程序替换它,在本例中为“ls”。
回答by duskwuff -inactive-
My intuition is I have to read the file and may be parse it to store the arguments in the arg. However I want to make sure.
我的直觉是我必须读取文件,并且可能会解析它以将参数存储在 arg 中。不过我想确定一下。
Your intuition is largely correct. The catutility that you're using as an example has two separate code paths:
你的直觉在很大程度上是正确的。cat您用作示例的实用程序有两个单独的代码路径:
- If there are filenames specified as arguments, it will open and read each one in turn.
- If there are no filenames specified, it will read from standard input.
- 如果有指定为参数的文件名,它将依次打开并读取每个文件名。
- 如果没有指定文件名,它将从标准输入中读取。
This behavior is specifically implemented in the catutility -- it is not implemented at any lower level. In particular, it is definitely not part of the execsystem call. The execsystem calls do not "look at" arguments at all; they just pass them straight on to the new process in argv, and that process gets to handle them however it sees fit.
此行为是在cat实用程序中专门实现的——它没有在任何较低级别实现。特别是,它绝对不是exec系统调用的一部分。该exec系统调用不“看”的所有参数; 他们只是将它们直接传递给 中的新进程argv,然后该进程可以按照它认为合适的方式处理它们。

