我知道execvp可以用于执行简单的命令,如下所示:
char* arg[] = {"ls", "-l", NULL};
execvp(arg[0],arg);我想知道当我运行execvp时这里发生了什么。在手册页中,它说execvp用新的进程映像替换了进程映像。然而,在这里我运行的是命令,而不是可执行文件。
具体地说,假设有一个命令特别需要输入,例如cat。如果我有一个文本文件text.txt,其中包含cat期望的文件名,并且我将标准输入重定向到该文件的文件流,那么execle("cat","cat",NULL)或execvp("cat", arg) (显然是arg存储"cat"和NULL的位置)的输出是否会像cat /filename那样在控制台中产生输出?我的直觉是,我必须读取文件,并可能对其进行解析以将参数存储在arg中。不过,我想确认一下。
提前感谢!
发布于 2013-01-13 15:56:10
下面是在execvp调用中发生的事情:
如果适用,
PATH中搜索要执行的文件。类UNIX系统中的大多数(如果不是全部)命令都是可执行的。如果不是,会发生什么?试试看。看看how glibc does it.execve。execve的某些部分可以在libc中实现,也可以是系统调用(如Linux)。execvp调用的参数设置参数和环境、找到适合加载二进制文件的处理程序,并将当前任务( execvp调用者)设置为不执行来准备程序。你可以找到它的实现here.以上所有步骤都符合相关manual pages中描述的POSIX设置的要求。
发布于 2013-01-14 07:10:18
关于你的问题:
在手册页中说,
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的地址空间替换当前进程的地址空间。
我的直觉是,我必须读取文件,并且可能会解析它,以便将参数存储在
中。
你确实有你。但是你也可以使用一些内核中的函数来实现"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 =)中打印还是很有趣的。
顺便说一句。您所描述的问题非常普遍,以至于有一个名为xargs的特殊可执行文件(在非常简单的解释中),它执行通过标准输入传递的参数列表上的给定程序。有关更多信息,请咨询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内部情况的信息(包括继承内容)可以在Advanced Programming in the UNIX Environment (2nd Edition) by W. Richard Stevens and Stephen A. Rago,也就是APUE2中找到。
如果您对UNIX内部原理感兴趣,那么您可能应该阅读它。
发布于 2013-01-13 15:21:52
"ls“不仅仅是一个命令,它实际上是一个程序(大多数命令都是)。当你像那样运行execvp时,它会破坏你的整个程序,它的内存,它的堆栈,它的堆,等等。在概念上“清除它”,并将它赋予"ls“,这样它就可以将它用于自己的堆栈、堆等。
简而言之,execvp将销毁您的程序,并将其替换为另一个程序,在本例中为"ls“。
https://stackoverflow.com/questions/14301407
复制相似问题