开发者

Difference between "system" and "exec" in Linux?

What 开发者_如何学Pythonis the difference between system and exec family commands? Especially I want to know which one of them creates child process to work?


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.

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

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().

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.


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.


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.


To create a process:

  • fork(2), a system call directly to the kernel

To execute a program, replacing the current image:

  • execve(2), a system call directly to the kernel, usually just called exec

To wait for a child process to finish:

  • wait(2), a system call directly to the kernel

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

  • system(3), a library function

To get the man pages for all of the above:

   $ man 2 fork execve wait
   $ man 3 system


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.

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.

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.


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.

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!



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.

  • If either the fork fails or waitpid returns an error other than EINTR, system returns –1 with errno set to indicate the error.
  • If the exec fails, implying that the shell can't be executed, the return value is as if the shell had executed 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.

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.

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


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

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.


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.

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.

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 :-).


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

some code...

exec('ls -l')

echo "1 2 3" // This will not executed in bash (as exec command use same 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.


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.

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.

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.


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:

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.

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 ....")".

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.

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜