it-roy-ru.com

Разница между "системой" и "exec" в Linux?

В чем разница между командами семейства system и exec? Особенно я хочу знать, какой из них создает дочерний процесс для работы?

63
Kamil

system() вызывает sh для обработки вашей командной строки, чтобы вы могли получить подстановочный знак и т. д. exec() и его друзья заменяют текущий образ процесса новым образом процесса.

С system() ваша программа продолжает работать, и вы получаете некоторое состояние о внешней команде, которую вы вызвали. С exec() ваш процесс стирается.

В общем, я думаю, вы могли бы думать о system() как о высокоуровневом интерфейсе. Вы можете продублировать его функциональность самостоятельно, используя комбинацию fork(), exec() и wait().

Чтобы ответить на ваш последний вопрос, system() вызывает создание дочернего процесса, а exec() - нет. Вы должны будете использовать fork() для этого.

84
Carl Norum

Функция exec заменяет текущий запущенный образ процесса при успешном завершении, дочерний элемент не создается (если вы сами не сделали этого ранее с fork()). Функция system () выполняет ветвление дочернего процесса и возвращает результат по завершении выполнения указанной команды или возникновении ошибки.

19
BobbyShaftoe

system() выполнит предоставленную команду в дочернем процессе, который она порождает. exec() заменит текущий процесс вызовом нового исполняемого файла, который вы укажете. Если вы хотите порождать дочерний процесс с помощью exec, вам придется fork() вашего процесса заранее.

7
Timo Geusch

Чтобы создать процесс:

  • fork(2), системный вызов напрямую в ядро

Чтобы выполнить программу, заменив текущее изображение:

  • execve(2), системный вызов непосредственно в ядро, обычно называемый exec

Чтобы дождаться завершения дочернего процесса:

  • wait(2), системный вызов напрямую в ядро

Чтобы запустить программу в командной консоли в дочернем процессе и дождаться ее завершения:

  • system(3), библиотечная функция

Чтобы получить справочные страницы для всего вышеперечисленного:

   $ man 2 fork execve wait
   $ man 3 system
6
DigitalRoss

system () вызовет командную оболочку вашей системы по умолчанию, которая выполнит командную строку, переданную в качестве аргумента, которая сама может создавать или не создавать дальнейшие процессы, которые будут зависеть от команды и системы. В любом случае, по крайней мере, будет создан командный процесс Shell.

С помощью system () вы можете вызывать любую команду, тогда как с помощью exec () вы можете вызывать только исполняемый файл. Сценарии оболочки и командные файлы должны выполняться командой Shell.

В основном они совершенно разные используются для разных целей. Более того, exec () заменяет вызывающий процесс и не возвращает. Более полезным было бы сравнение между system () и spawn (). Хотя система может быть проще вызывать, она возвращает значение, которое сообщает вам, была ли вызвана команда Shell, и ничего не говорит об успешности самой команды. С помощью spawn () вы можете получить код завершения процесса; условно, ненулевой используется для указания условий ошибки. Как и exec (), spawn () должен вызывать исполняемый файл, а не скрипт Shell или встроенную команду.

2
Clifford

int system(const char *cmdstring);

Пример: system("date > file");


В общем, system реализуется путем вызова fork, exec и waitpid , есть три типа возвращаемых значений.

  • Если разветвление завершается с ошибкой или waitpid возвращает ошибку, отличную от EINTR, система возвращает -1 с errno set, чтобы указать ошибку.
  • Если exec завершается неудачно, подразумевая, что Shell не может быть выполнена, возвращаемое значение такое, как если бы Shell выполнила Exit (127).
  • В противном случае все три функции - fork, exec и waitpid - завершаются успешно, а возвращаемое значение из system является состоянием завершения оболочки в формате, указанном для waitpid.

Функция fork предназначена для создания нового процесса (дочернего), который затем Вызывает выполнение другой программы, вызывая одну из функций exec . Когда процесс вызывает одну из функций Exec, этот процесс полностью заменяется новой программой, и новая программа начинает выполнять в своей основной функции. Идентификатор процесса не изменяется в 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 []);

2
Madhavan G

Существуют некоторые существенные различия между 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
        }
     }
  }
}

В этой последовательности есть и другие тонкости, которые могут быть определены тщательным чтением соответствующих man-страниц, но этот код будет хорошо работать при отсутствии сигналов, нескольких дочерних процессов и т.д. Кроме того, встроенные объявления могут ограничивать область действия переменные, но включены, чтобы этот код можно было использовать в качестве шаблона, который работает (вы можете использовать другой стиль кодирования :-).

1
Jon Spencer

exec () заменяет текущий запущенный процесс на образ процесса выполняемой функции. С помощью этого можно вызывать только исполняемые файлы.

system () неявно запускает новый процесс для обслуживания запроса и возвращает значение, полученное через дочерний процесс, который он изначально разветвил. Для выполнения операции используется системная оболочка по умолчанию.

1
Morpheus

system () вызывает нужную программу или встроенную команду с помощью командной консоли, это неэффективный способ, потому что оболочка запускается до запуска программы. 

В случае семейства системных вызовов exec создается совершенно новый образ, то есть они заменяют текущий процесс новым процессом, указанным путем, файлом или любым другим аргументом, который вы упоминаете.

Следует иметь в виду, что при использовании семейства системных вызовов exec исходная программа больше не будет работать после запуска новой.

0
kishanp

System () создаст дочерний процесс и вызовет другую подпрограмму Shell, в то время как exec () не создаст дочерний процесс. Given Example удалит разницу.

какой-то код ...

exec ('ls -l')

echo "1 2 3" // Это не будет выполнено в bash (так как команда exec использует тот же Shell)

какой-то код ...

system (ls -l) echo "1 2 3" // Это будет выполнено после завершения дочернего процесса System, так как они отличаются от родительского PID. 

0
Poseidon_Geek

В общем, «система» настолько неэффективна, и вы не должны использовать ее, если у вас нет небольшого кода. Если вам нужно выполнить несколько программ в вашем процессе, вам лучше использовать fork & exec, хотя вы делаете это более сложным . Вот список различий между ними:

1- «системная» команда создает копию оболочки для выполнения вашей программы. Каждый раз, когда вы вызываете систему, вы создаете копию Shell. Так что не используйте его, когда у вас есть много программ для выполнения внутри вашего процесса.

2- В частности, если вы хотите выполнять системные функции, такие как "mv", "mkdir", было бы лучше использовать процедуры, такие как mkdir (), unlink () или remove (), вместо того, чтобы выполнять их через "system (") рм .... ") или системный (" мкдир .... ")".

3. Поскольку система вызывает Shell для выполнения желаемой программы, у вас могут возникнуть проблемы с правами доступа пользователя. Например, кто-то может взломать ваш код и выполнить что-то другое вместо программы, которую вы намеревались выполнить с помощью системной команды.

Для получения дополнительной информации вы можете прочитать главу 11 этой книги: «Программирование в UNIX» Дэвида Карри.

0
ImanKh

Ответ 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
        }
     }
  }
}

(Укажите, что у меня пока недостаточно репутации, чтобы комментировать сообщение Джона, поэтому я отредактировал его. Некоторые люди отклонили издание, попросив меня ответить на вопрос, а не редактировать его, но я думаю, что в этом случае это намного проще, практичнее и ясно отредактировать существующий код, просто исправляя небольшую ошибку, чем писать полный текст/вставить/изменить ответ.) В любом случае, спасибо JonSpencer за ваш ответ, это было действительно полезно для меня!

0
jap jap