Linux中的“system”和“exec”有什么區別?

[英]Difference between “system” and “exec” in Linux?


What is the difference between system and exec family commands? Especially I want to know which one of them creates child process to work?

系統和exec家族命令有什么區別?特別是我想知道哪一個創建子過程來工作?

12 个解决方案

#1


80  

system() calls out to sh to handle your command line, so you can get wildcard expansion, etc. exec() and its friends replace the current process image with a new process image.

system()調用sh來處理命令行,這樣您就可以獲得通配符展開等exec()和它的朋友用一個新的進程映像替換當前的進程映像。

With system(), your program continues running and you get back some status about the external command you called. With exec(), your process is obliterated.

使用system(),您的程序繼續運行,您將獲得有關調用的外部命令的一些狀態。通過exec(),您的流程將被刪除。

In general, I guess you could think of system() as a higher-level interface. You could duplicate its functionality yourself using some combination fork(), exec(), and wait().

一般來說,我認為您可以將system()視為一個高級接口。您可以使用一些組合fork()、exec()和wait()來復制其功能。

To answer your final question, system() causes a child process to be created, and the exec() family do not. You would need to use fork() for that.

要回答最后一個問題,system()會創建子進程,而exec()家族不會。為此需要使用fork()。

#2


18  

The exec function replace the currently running process image when successful, no child is created (unless you do that yourself previously with fork()). The system() function does fork a child process and returns when the command supplied is finished executing or an error occurs.

當成功時,exec函數將替換當前正在運行的進程映像,不會創建任何子進程(除非您以前使用fork()創建子進程映像)。函數的作用是:在執行完所提供的命令或發生錯誤時返回子進程。

#3


6  

system() will execute the supplied command in a child process that it spawns. exec() will replace the current process with the invocation of the new executable that you specify. If you want to spawn a child process using exec, you'll have to fork() your process beforehand.

system()將在生成的子進程中執行所提供的命令。exec()將用您指定的新可執行文件的調用替換當前進程。如果您想要使用exec生成子進程,那么您必須預先為您的進程提供fork()。

#4


5  

To create a process:

創建一個過程:

  • fork(2), a system call directly to the kernel
  • fork(2),系統直接調用內核

To execute a program, replacing the current image:

執行程序,替換當前圖像:

  • execve(2), a system call directly to the kernel, usually just called exec
  • execve(2),直接調用內核的系統調用,通常稱為exec

To wait for a child process to finish:

等待子進程完成:

  • wait(2), a system call directly to the kernel
  • 等待(2),系統直接調用內核

To run a program in a shell in a child process and wait for it to finish:

在子進程的shell中運行程序並等待它完成:

  • system(3), a library function
  • 系統(3),一個庫函數

To get the man pages for all of the above:

為了獲得以上所有的手冊頁:

   $ man 2 fork execve wait
   $ man 3 system

#5


2  

system() will invoke your systems default command shell, which will execute the command string passed as an argument, that itself may or may not create further processes, that would depend on the command and the system. Either way, at least a command shell process will be created.

system()將調用您的系統默認命令shell,它將執行作為參數傳遞的命令字符串,該字符串本身可能會創建,也可能不會創建進一步的進程,這將取決於命令和系統。無論哪種方式,至少將創建一個命令shell進程。

With system() you can invoke any command, whereas with exec(), you can only invoke an executable file. Shell scripts and batch files must be executed by the command shell.

使用system()可以調用任何命令,而使用exec()則只能調用可執行文件。Shell腳本和批處理文件必須由命令Shell執行。

Basically they are entirely different used for different purposes. Moreover exec() replaces the calling process, and does not return. A more useful comparison would be between system() and spawn(). While system may be simpler to invoke, it returns a value that tells you whether the command shell was invoked, and tells you nothing about the success of the command itself. With spawn() you can get the process's exit code; by convention non-zero is used to indicate error conditions. Like exec() spawn() must invoke an executable, not a shell script or built-in command.

基本上它們是完全不同的用於不同的目的。此外,exec()替換調用進程,並且不返回。一個更有用的比較是system()和spawn()。雖然系統可能更容易調用,但它會返回一個值,該值告訴您是否調用了命令shell,並且不會告訴您命令本身的成功。使用spawn()可以獲得進程的退出代碼;根據約定非零是用來表示錯誤條件的。與exec() spawn()一樣,必須調用可執行文件,而不是shell腳本或內置命令。

#6


1  

exec() replaces the current running process with the process image of the function being performed..only executable files can be invoked using this.

exec()將當前運行的進程替換為正在執行的函數的進程映像。只有可執行文件可以使用這個調用。

system() forks off a new process implicitly to service the request and returns the value it obtained through the child process it forked initially.It uses the system's default shell to carry out the operation.

system()隱式地派生一個新進程來服務請求,並返回通過最初分叉的子進程獲得的值。它使用系統的默認shell執行操作。

#7


1  


int system(const char *cmdstring);

Ex: system("date > file");

例:系統(“日期>文件”);


In general, system is implemented by calling fork, exec, and waitpid, there are three types of return values.

通常,系統是通過調用fork、exec和waitpid實現的,有三種返回值。

  • If either the fork fails or waitpid returns an error other than EINTR, system returns –1 with errno set to indicate the error.
  • 如果fork失敗或waitpid返回除EINTR之外的錯誤,則系統返回-1,並設置errno以指示錯誤。
  • If the exec fails, implying that the shell can't be executed, the return value is as if the shell had executed exit(127).
  • 如果exec失敗,意味着shell無法執行,則返回值就像shell已執行exit(127)一樣。
  • Otherwise, all three functions—fork, exec, and waitpid—succeed, and the return value from system is the termination status of the shell, in the format specified for waitpid.
  • 否則,所有三個功能- fork、exec和waitpid -成功,系統的返回值是shell的終止狀態,以waitpid指定的格式。

The fork function is to create a new process (the child) that then causes another program to be executed by calling one of the exec functions. When a process calls one of the exec functions, that process is completely replaced by the new program, and the new program starts executing at its main function. The process ID does not change across an exec, because a new process is not created; exec merely replaces the current process—its text, data, heap, and stack segments—with a brand new program from disk.

fork函數是創建一個新進程(子進程),然后通過調用其中一個exec函數來執行另一個程序。當一個進程調用其中一個exec函數時,該進程被新程序完全替換,新程序開始在其主函數處執行。進程ID在exec中不會發生變化,因為沒有創建新的進程;exec只是用一個全新的磁盤程序替換當前進程——它的文本、數據、堆和堆棧段。

There are six different exec functions,

有六個不同的執行函數,


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


0  

System() will create child process and invoke another sub shell while exec() will not create child process.Given Example will clear difference.

系統()將創建子進程並調用另一個子shell,而exec()將不會創建子進程。舉個例子就可以清楚地看出區別。

some code...

一些代碼…

exec('ls -l')

exec(' ls - l ')

echo "1 2 3" // This will not executed in bash (as exec command use same shell)

echo "1 2 3" //這不會在bash中執行(作為執行命令使用相同的shell)

some code ...

一些代碼…

system (ls -l) echo "1 2 3" // This will be executed after finishing System child process as they are different from parent PID.

系統(ls -l)回顯“1 2 3”//這將在完成系統子進程之后執行,因為它們與父PID不同。

#9


0  

system() invokes the desired program or built-in command using a shell, this is an inefficient way because a shell is started before the program is started.

system()使用shell調用所需的程序或內置命令,這是一種低效的方式,因為在啟動程序之前啟動shell。

In the case of the exec family of system calls, a whole new image is being created, that is, they replace the current process with a new process specified by the path or file or whatever argument you are mentioning.

在系統調用的exec族中,正在創建一個全新的映像,也就是說,它們用路徑或文件或您所提到的任何參數指定的新進程替換當前進程。

The thing to be kept in mind is that, when the exec family of system calls are used, the original program will no longer be running after the new one is started.

需要記住的是,當使用exec系列的系統調用時,在啟動新程序后,原始程序將不再運行。

#10


0  

There are some significant differences between exec(2) and system(3) that should be kept in mind. system() returns to the caller, whereas exec() replaces the existing code with the new image. This has been explained above.

exec(2)和system(3)之間有一些需要記住的顯著差異。system()返回給調用者,而exec()用新映像替換現有代碼。上面已經解釋過了。

However, the not so subtle difference comes when you want to run a procedure and then return to your existing code, receiving the return code from the invoked procedure. system() does provide a return code, but the return code can only be used to detect an error condition, and cannot be used to recover a return code.

但是,當您想要運行一個過程,然后返回到您的現有代碼,從被調用的過程接收返回代碼時,就會出現不那么微妙的差異。system()確實提供了返回代碼,但是返回代碼只能用於檢測錯誤條件,不能用於恢復返回代碼。

One possible proper sequence of system calls is:

系統調用的一個可能的適當序列是:

#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
        }
     }
  }
}

There are other subtleties to this sequence which can be determined by a careful reading of the relevant man pages, but this code will work fine in the absence of signals, multiple child processes, etc. Also, the inline declarations may limit the scope of the variables, but are included to allow this code to be used as a template that works (you may use a different coding style :-).

還有其他細節這個序列可由仔細閱讀相關的手冊頁,但是這段代碼將在沒有信號的情況下,可以多個子流程,等。同時,內聯聲明可能會限制變量的范圍,但包括允許這段代碼被用作一種有效的模板(您可能使用不同的編碼風格:-)。

#11


0  

In general, "system" is so inefficient and you should not use it unless you have a small code. If you need to execute several programs in your process, you would better use fork&exec though you make it more complicated. Here is a list of differences between them:

一般來說,“系統”是非常低效的,除非您有一個小的代碼,否則不應該使用它。如果你需要在你的過程中執行幾個程序,你最好使用fork&exec,盡管你把它變得更復雜。以下是他們之間的不同之處:

1- "system" command creates a copy of shell to execute your program. Every time you call a system, you create a copy of shell. So do not use it when you have lots of programs to execute inside your process.

1-“系統”命令創建shell的副本以執行程序。每次調用系統時,都要創建shell的副本。因此,當您有許多程序要在流程中執行時,不要使用它。

2- Specifically, if you want to execute system functions such as "mv", "mkdir", it would be better to use routines such as mkdir(), unlink() or remove() instead of executing them through "system("rm ....") or system("mkdir ....")".

2 -特別是如果你想執行系統功能如“mv”、“mkdir”,將是更好的使用例程如mkdir()、分離()或刪除()而不是執行他們通過“系統(rm ....)或系統(mkdir ....)”。

3- Since system calls shell to execute your desired program, you may have some user permission problems. For example, someone may crack your code and execute something else instead of the program you intended to execute through system command.

3-由於系統調用shell來執行您想要的程序,您可能會遇到一些用戶權限問題。例如,有人可能會破解您的代碼並執行其他東西,而不是您想通過system命令執行的程序。

For more information, you may read chapter 11 of this book: "UNIX Systems Programming" by David Curry.

要了解更多信息,請閱讀這本書的第11章:David Curry寫的“UNIX系統編程”。

#12


0  

JonSpencer answer is fine, except that child_status must be an int (no a pointer to int) and has to be passed to wait function by reference.

JonSpencer的回答是可以的,但是child_status必須是int(沒有指向int的指針),並且必須通過引用傳遞來等待函數。

So, the code would be mainly the same, just changing those couple of things:

所以代碼基本上是一樣的,只是改變了這兩點

#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
        }
     }
  }
}

(Point out that I don't have enough reputation yet to comment Jon's post so I edited it. Some people rejected the edition asking me to answer the question instead of editing it, but I think that in this case it is much simpler, practical and clear to edit an existing code just correcting a small mistake than to write a full copy/paste/modify answer.) Anyway, thanks JonSpencer for your answer, it was really useful for me!

(指出我還沒有足夠的聲譽來評論Jon的文章,所以我編輯了它。有些人拒絕讓我回答問題而不是編輯問題的版本,但我認為在這種情況下,編輯現有的代碼只是糾正一個小錯誤比編寫完整的拷貝/粘貼/修改答案要簡單、實用、清晰得多。無論如何,謝謝你的回答,這對我很有用!


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2009/11/08/72f5d74f7979d438305564740233383e.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com