Linux系统和exec之间的区别?

systemexec系列命令有什么区别? 特别是我想知道他们中的哪一个创造了孩子的工作过程?

system()调用sh来处理你的命令行,这样你可以得到通配符扩展等等exec()及其朋友用当前进程映像replace当前进程映像。

使用system() ,程序会继续运行,并返回有关您调用的外部命令的一些状态。 用exec() ,你的过程被抹杀了。

一般来说,我想你可以把system()看作更高层次的接口。 您可以使用fork()exec()wait()来组合自己的function。

为了回答你最后的问题, system()会导致创build一个subprocess,而exec()系列则不会。 你将需要使用fork()

exec函数在成功时replace当前正在运行的进程映像,不会创buildsubprocess(除非您以前使用fork() )。 system()函数为subprocess分叉,并在提供的命令执行完成或发生错误时返回。

system()将在它所产生的subprocess中执行提供的命令。 exec()将用您指定的新可执行文件的调用replace当前进程。 如果你想用exec生成一个subprocess,你必须事先fork()你的进程。

创build一个stream程:

  • fork(2) ,系统直接调用内核

要执行程序,请replace当前图像:

  • execve(2)直接调用内核的系统调用,通常只是调用exec

等待subprocess完成:

  • wait(2) ,直接向系统调用内核

在subprocess中的shell中运行一个程序并等待它完成:

  • system(3) ,库函数

要获得以上所有的手册页 :

  $ man 2 fork execve wait $ man 3 system 

system()会调用你的系统默认命令shell,它会执行作为parameter passing的命令string,它本身可能会或可能不会创build进一步的进程,这取决于命令和系统。 无论哪种方式,至less一个命令shell程序将被创build。

使用system(),你可以调用任何命令,而使用exec(),你只能调用一个可执行文件。 Shell脚本和batch file必须由命令行执行。

基本上它们完全不同,用于不同的目的。 而且exec()取代了调用过程,并没有返回。 system()和spawn()之间更有用的比较。 虽然系统调用起来可能更简单,但它会返回一个值,告诉您命令shell是否被调用,并且不告诉您该命令本身是否成功。 用spawn()你可以得到进程的退出代码; 按照惯例,非零用于表示错误情况。 像exec()spawn()必须调用可执行文件,而不是shell脚本或内置命令。

exec()用正在执行的函数的进程映像replace当前正在运行的进程。只有可执行文件可以使用这个调用。

system()会隐式地派生一个新的进程来为请求提供服务,并返回它通过它最初派生的subprocess获得的值。它使用系统的默认shell来执行操作。


 int system(const char *cmdstring); 

例如: system("date > file");


一般来说, 系统是通过调用fork,exec和waitpid来实现的,返回值有三种types。

  • 如果fork失败或者waitpid返回EINTR以外的错误,则系统返回-1,并将errno设置为指示错误。
  • 如果exec失败,意味着shell不能被执行,返回值就好像shell已经执行了exit(127)。
  • 否则,所有三个函数fork,exec和waitpid成功,并且系统的返回值是shell的终止状态,采用waitpid指定的格式。

fork函数是创build一个新的进程(subprocess),然后通过调用其中一个exec函数来执行另一个程序。 当一个进程调用其中一个exec函数时,该进程被新程序完全replace,新程序开始在其主函数中执行。 进程标识不会跨exec执行,因为不会创build新进程; exec只是用磁盘上的一个全新的程序来replace当前的进程 – 它的文本,数据,堆和堆栈段。

有六个不同的执行function


 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 []); 

System()将创buildsubprocess并调用另一个子shell,而exec()将不会创buildsubprocess。给出示例将明确区别。

一些代码…

exec('ls -l')

回声“1 2 3”//这将不会在bash中执行(因为exec命令使用相同的shell)

一些代码…

系统(ls -l)echo“1 2 3”//这将在完成系统subprocess后执行,因为它们与父PID不同。

system()使用shell调用所需的程序或内置命令,这是一种效率低下的方式,因为在程序启动之前启动了一个shell。

在系统调用的exec系列的情况下,正在创build一个全新的映像,也就是说,它们将使用由path或文件指定的新进程或您提到的任何参数来replace当前进程。

需要记住的是,当使用系统调用的exec系列时,原来的程序在新的程序启动后将不再运行。

exec(2)system(3)应该牢记一些重要的区别。 system()返回给调用者,而exec()用新的图像replace现有的代码。 这已经在上面解释过了。

但是,当你想运行一个过程,然后返回到你现有的代码,从被调用的过程接收返回代码时,就不会有那么微妙的差别了。 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 } } } } 

这个序列还有其他的细节可以通过仔细阅读相关的手册页来确定,但是这个代码在没有信号,多个subprocess等情况下可以正常工作。另外,内联声明可能会限制variables,但是包含它们是为了让这个代码可以用作一个可以工作的模板(你可以使用不同的编码风格:-)。

一般来说,“系统”效率太低,除非你有小代码,否则不应该使用它。 如果你需要在你的程序中执行几个程序,你可以使用fork&exec来更好地使用它。 以下是他们之间的差异列表:

1-“系统”命令创build一个shell的副本来执行你的程序。 每次调用系统时,都会创build一个shell的副本。 所以当你有很多程序在你的进程中执行的时候不要使用它。

具体来说,如果要执行“mv”,“mkdir”等系统函数,最好使用例如mkdir(),unlink()或remove()的例程,而不是通过“system(” rm ….“)或系统(”mkdir ….“)”。

3-由于系统调用shell来执行你想要的程序,你可能会遇到一些用户权限问题。 例如,有人可能会破解你的代码并执行其他的东西,而不是你想通过系统命令执行的程序。

有关更多信息,请阅读本书的第11章:David Curry的“UNIX系统编程”。

JonSpencer的答案是好的,除了child_status必须是一个int(不是指向int的指针),必须通过引用传递给wait函数。

所以,代码将是相同的,只是改变这些事情:

 #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的post,所以我编辑了它,有人拒绝了这个版本,要求我回答这个问题,而不是编辑它,但是我认为在这种情况下,它更简单,更实用并清除编辑现有的代码只是纠正一个小错误,而不是写一个完整的复制/粘贴/修改答案。)无论如何,感谢JonSpencer你的答案,这对我来说真的很有用!