Linux 中“system”和“exec”有什么区别?
- 2024-10-24 08:50:00
- admin 原创
- 88
问题描述:
system
和系列命令之间有什么区别exec
?特别是我想知道其中哪一个会创建子进程来工作?
解决方案 1:
system()
调用来sh
处理您的命令行,以便您可以获得通配符扩展等。 exec()
并且它的朋友用新的进程映像替换当前进程映像。
使用system()
,您的程序将继续运行,并且您会获得有关所调用的外部命令的一些状态。使用exec()
,您的进程将被消灭。
总的来说,我想你可以将其视为system()
一个更高级别的接口。你可以使用fork()
、exec()
和 的某种组合自己复制其功能wait()
。
回答你的最后一个问题,system()
会导致创建子进程,而exec()
家族进程不会。你需要使用fork()
它。
解决方案 2:
exec 函数成功时会替换当前正在运行的进程映像,不会创建子进程(除非您之前自己使用 执行了此操作fork()
)。 system() 函数会派生一个子进程,并在提供的命令执行完毕或发生错误时返回。
解决方案 3:
system()
将在其生成的子进程中执行提供的命令。exec()
将用您指定的新可执行文件的调用替换当前进程。如果您想使用 生成子进程exec
,则必须fork()
事先设置您的进程。
解决方案 4:
要创建流程,请执行以下操作:
fork(2)
,直接对内核进行系统调用
要执行程序,替换当前图像:
execve(2)
,直接对内核进行系统调用,通常称为exec
等待子进程完成:
wait(2)
,直接对内核进行系统调用
要在子进程中的 shell 中运行程序并等待其完成:
system(3)
,库函数
要获取以上所有内容的手册页:
$ man 2 fork execve wait
$ man 3 system
解决方案 5:
system() 将调用系统默认的命令 shell,它将执行作为参数传递的命令字符串,该命令字符串本身可能会或可能不会创建进一步的进程,这取决于命令和系统。无论哪种方式,至少会创建一个命令 shell 进程。
使用 system() 可以调用任何命令,而使用 exec() 只能调用可执行文件。Shell 脚本和批处理文件必须由命令 shell 执行。
基本上,它们完全不同,用于不同的目的。此外,exec() 替换了调用进程,并且不返回。更有用的比较是 system() 和 spawn()。虽然 system 调用起来可能更简单,但它会返回一个值,告诉您是否调用了命令 shell,而不会告诉您命令本身是否成功。使用 spawn(),您可以获取进程的退出代码;按照惯例,非零用于指示错误情况。与 exec() 一样,spawn() 必须调用可执行文件,而不是 shell 脚本或内置命令。
解决方案 6:
JonSpencer 的回答很好,除了 child_status 必须是一个 int(不能是指向 int 的指针)并且必须通过引用传递给等待函数。
因此,代码基本相同,只需改变以下几点:
#include <unistd.h>
#include <sys/wait.h>
#define NUMARGS 2
int main (int argc, char *argv[])
{
pid_t child_pid, wait_pid;
int child_status;
char * exec_path = "/path/to/executable";
char * child_args[NUMARGS] = {0,0};
child_pid = fork();
if (0 == child_pid)
{ // In child process
...
int child_ret_code = execv(exec_path, child_args); //or whichever flavor of exec() that floats your boat
... // if child_ret_code = -1, process execv() error return
}
else if (-1 == child_pid)
{
... //process error return from fork
}
else if (0 < child_pid)
{ // Parent process
wait_pid = wait(&child_status);
if (-1 == wait_pid)
{
... //Process error return from wait()
}
else
{ // Good fork/exec/wait
if (WIFEXITED(child_status)) // Child exited normally and hopefully returned exit code
{
int child_ret_code = WEXITSTATUS(child_status);
... // Continue on as you would after call to system(3)
// except now you have the return code you needed
}
}
}
}
(指出我还没有足够的声誉来评论 Jon 的帖子,所以我对其进行了编辑。有些人拒绝了该版本,要求我回答问题而不是编辑它,但我认为在这种情况下,编辑现有代码以纠正一个小错误比写完整的复制/粘贴/修改答案要简单、实用和清晰得多。)无论如何,感谢 JonSpencer 的回答,这对我真的很有用!
解决方案 7:
int system(const char *cmdstring);
前任:system("date > file");
一般来说,system是通过调用fork 、 exec 、 waitpid来实现的,返回值有三种类型。
如果 fork 失败或者 waitpid 返回 EINTR 以外的错误,系统将返回 -1 并设置 errno 来指示错误。
如果 exec 失败,意味着无法执行 shell,返回值就像 shell 执行了 exit(127) 一样。
否则,所有三个函数(fork、exec 和 waitpid)都将成功,并且系统的返回值是 shell 的终止状态,采用 waitpid 指定的格式。
fork函数用于创建一个新进程(子进程),然后通过调用其中一个exec函数来执行另一个程序。当某个进程调用其中一个 exec 函数时,该进程将完全被新程序替换,并且新程序将开始在其主函数中执行。进程 ID 在 exec 中不会改变,因为不会创建新进程;exec 只是用磁盘上的全新程序替换当前进程(其文本、数据、堆和堆栈段)。
有六种不同的 exec 函数,
int execl(const char *pathname, const char *arg0, ... /* (char *)0 */ );
int execv(const char *pathname, char *const argv []);
int execle(const char *pathname, const char *arg0, .../* (char *)0, char *const envp[] */ );
int execve(const char *pathname, char *const argv[], char *const envp []);
int execlp(const char *filename, const char *arg0,... /* (char *)0 */ );
int execvp(const char *filename, char *const argv []);
解决方案 8:
exec() 用正在执行的函数的进程映像替换当前正在运行的进程。只有可执行文件才能使用它来调用。
system() 隐式地分叉一个新进程来服务请求,并返回它通过最初分叉的子进程获得的值。它使用系统的默认 shell 来执行操作。
解决方案 9:
exec(2)
和之间存在一些显著差异,system(3)
应牢记在心。 system()
返回给调用者,而exec()
用新图像替换现有代码。 上面已经解释过了。
但是,当您想要运行一个过程然后返回到现有代码并接收来自被调用过程的返回代码时,就会出现不太微妙的差别。 system()
确实提供了返回代码,但返回代码只能用于检测错误情况,不能用于恢复返回代码。
系统调用的一个可能的正确序列是:
#include <unistd.h>
#include <sys/wait.h>
#define NUMARGS 2
int main (int argc, char *argv[])
{
pid_t child_pid, wait_pid;
int * child_status;
char * exec_path = "/path/to/executable";
char * child_args[NUMARGS] = {0,0};
child_pid = fork();
if (0 == child_pid)
{ // In child process
...
int child_ret_code = execv(exec_path, child_args); //or whichever flavor of exec() that floats your boat
... // if child_ret_code = -1, process execv() error return
}
else if (-1 == child_pid)
{
... //process error return from fork
}
else if (0 < child_pid)
{ // Parent process
wait_pid = wait(child_status);
if (-1 == wait_pid)
{
... //Process error return from wait()
}
else
{ // Good fork/exec/wait
if (WIFEXITED(child_status)) // Child exited normally and hopefully returned exit code
{
int child_ret_code = WEXITSTATUS(child_status);
... // Continue on as you would after call to system(3)
// except now you have the return code you needed
}
}
}
}
通过仔细阅读相关的手册页可以确定这个序列的其他微妙之处,但是,在没有信号、多个子进程等的情况下,此代码将正常工作。此外,内联声明可能会限制变量的范围,但包含在内以允许将此代码用作可工作的模板(您可以使用不同的编码风格:-)。
解决方案 10:
System() 将创建子进程并调用另一个子 shell,而 exec() 不会创建子进程。给出的示例将清楚地显示差异。
一些代码...
执行('ls -l')
echo "1 2 3" // 这不会在 bash 中执行(因为 exec 命令使用相同的 shell)
一些代码...
系统(ls -l)echo“1 2 3”//这将在完成系统子进程后执行,因为它们与父 PID 不同。
解决方案 11:
system() 使用 shell 调用所需的程序或内置命令,这是一种低效的方式,因为在程序启动之前会启动 shell。
对于 exec 系列系统调用,将创建一个全新的图像,也就是说,它们用路径、文件或您提到的任何参数指定的新进程替换当前进程。
需要记住的是,当使用 exec 系列系统调用时,新程序启动后,原始程序将不再运行。
解决方案 12:
总的来说,“system” 效率太低,除非你的代码量很小,否则不要使用它。如果你需要在进程中执行多个程序,那么最好使用 fork&exec,尽管这样做会更复杂。下面列出了它们之间的区别:
1-“system”命令会创建一个 shell 副本来执行您的程序。每次调用系统时,您都会创建一个 shell 副本。因此,当您的进程内有大量程序要执行时,请不要使用它。
2- 具体来说,如果您想执行系统函数,例如“mv”、“mkdir”,最好使用 mkdir()、unlink() 或 remove() 等例程,而不是通过“system("rm ....") 或 system("mkdir ....")”执行它们。
3- 由于系统调用 shell 来执行您想要的程序,您可能会遇到一些用户权限问题。例如,有人可能会破解您的代码并执行其他程序,而不是您打算通过系统命令执行的程序。
欲了解更多信息,您可以阅读本书的第 11 章:David Curry 撰写的“UNIX 系统编程”。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件