[英]How does execvp run a command?
我知道execvp
可用于执行简单的命令,如下所示:
char* arg[] = {"ls", "-l", NULL};
execvp(arg[0],arg);
我想知道运行execvp
时在这里发生了什么。 在手册页中,它说execvp
用新的图像替换过程图像的图像。 但是在这里我运行的命令不是可执行文件。
具体来说,有一个命令特别需要输入,例如cat。 如果我有一个文本文件text.txt,其中包含cat所需的文件名,并且我将stdin重定向到文件的文件流,则会输出execle("cat","cat",NULL)
或execvp("cat", arg)
(很明显,arg存储"cat"
和NULL
)会导致控制台中的输出像cat /filename
一样? 我的直觉是我必须读取文件并可能解析它以将参数存储在arg中。 但是我想确定一下。
提前致谢!
以下是execvp
调用中发生的情况:
PATH
搜索要执行的文件。 类UNIX系统中的大多数(如果不是全部)命令都是可执行文件。 如果不是,会发生什么? 试试吧。 看看glibc是如何做到的 。 execve
。 execve
可以在libc中实现,也可以是系统调用(如在Linux中)。 execvp
调用,找到适合加载二进制文件的处理程序并设置当前程序来准备程序任务( execvp
调用者)没有执行。 你可以在这里找到它的实现。 上述所有步骤均符合POSIX设定的要求,相关手册页中对此进行了描述。
关于你的问题:
在手册页中,它说
execvp
用新的图像替换过程图像的图像。 但是在这里我运行的命令不是可执行文件。
很久以前shell非常有限,几乎所有的UNIX命令都是独立的可执行文件。 现在,主要是出于速度目的,UNIX命令的一些子集在shell本身内部实现,这些命令称为builtins
。 您可以通过type
命令检查shell中实现的内置命令是否为内置命令:
λ ~/ type echo
echo is a shell builtin
(可以在shell的man
页中找到包含描述的内置列表的完整列表,例如man bash-builtins
或man builtin
。)
但是仍然大多数命令仍然具有可执行文件:
λ ~/ whereis echo
/bin/echo
因此,在您运行的特定情况下:
char* arg[] = {"ls", "-l", NULL};
execvp(arg[0],arg);
实际上,您正在使用(最有可能) /bin/ls
地址空间替换当前进程的地址空间。
我的直觉是我必须读取文件并可能解析它以将参数存储在arg中。
的确,你有。 但你也可以使用一些内核函数来代表“shebang”:
而不是将文件名放在单独的文件中添加所谓的shebang作为您想要cat的文件的第一行:
#!/bin/cat
并添加chmod +x
。 然后你可以将它作为可执行文件运行(通过任何exec
函数或shell):
λ ~/tmp/ printf '#!/bin/cat\nTEST\n' > cat_me
λ ~/tmp/ chmod +x cat_me
λ ~/tmp/ ./cat_me
#!/bin/cat
TEST
因为它有一个缺点就是用文件打印shebang
本身,但在内核中执行它仍然很有趣=)
BTW。 您描述的问题是否如此常见,以至于存在一个名为xargs
的特殊可执行文件(在非常简单的解释中)在通过stdin传递的参数列表上执行给定程序。 有关更多信息,请咨询man xargs
。
为了便于记忆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 |
+----------+----------+----------+----------+--------+---------+--------+
所以在你的情况下execvp
需要文件名,argv( v )和environ( e )。 然后它尝试通过将filename
(在您的情况下为cat
)附加到PATH
每个路径组件来“猜测”路径名(也称为完整路径),直到找到具有可执行filename
路径。
关于在exec
的引擎下发生的更多信息(包括继承的东西)可以在W。Richard Stevens和Stephen A. Rago又名APUE2 的UNIX环境(第2版)的高级编程中找到。
如果您对UNIX内部感兴趣,您应该阅读它。
“ls”不仅仅是一个命令,它实际上是一个程序(大多数命令都是)。 当你运行这样的execvp时,它将会破坏你的整个程序,它的内存,它的堆栈,它的堆等......从概念上“清除它”并将它赋予“ls”以便它可以将它用于它自己的堆栈,堆等
简而言之,execvp将破坏您的程序,并将其替换为另一个程序,在本例中为“ls”。
我的直觉是我必须读取文件并可能解析它以将参数存储在arg中。 但是我想确定一下。
你的直觉基本上是正确的。 您作为示例使用的cat
实用程序具有两个单独的代码路径:
此行为在cat
实用程序中专门实现 - 它不在任何较低级别实现。 特别是,它绝对不是exec
系统调用的一部分。 exec
系统调用根本不“查看”参数; 他们只是直接将它们传递给argv
的新进程,并且该进程可以处理它们,但它认为合适。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.