Linux 中“system”和“exec”有什么区别?

2024-10-24 08:50:00
admin
原创
88
摘要:问题描述:system和系列命令之间有什么区别exec?特别是我想知道其中哪一个会创建子进程来工作?解决方案 1:system()调用来sh处理您的命令行,以便您可以获得通配符扩展等。 exec()并且它的朋友用新的进程映像替换当前进程映像。使用system(),您的程序将继续运行,并且您会获得有关所调用的外...

问题描述:

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 系统编程”。

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用