Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

Ответ 3

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

Ответ 4

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

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

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

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

Ожидание завершения дочернего процесса:

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

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

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

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

   $ man 2 fork execve wait
   $ man 3 system

Ответ 5

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

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

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

Ответ 6


int system(const char *cmdstring);

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


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

  • Если либо сбой fork, либо waitpid возвращает ошибку, отличную от EINTR, система возвращает -1 с набором errno для указания ошибки.
  • Если exec не работает, подразумевая, что оболочка не может быть выполнена, возвращаемое значение будет таким, как если бы оболочка была выполнена выхода (127).
  • В противном случае все три функции-fork, exec и waitpid-success и возвращаемое значение из системы это статус завершения оболочки, в формате, указанном для 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 []);

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

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

некоторый код...

exec ('ls -l')

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

некоторый код...

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

Ответ 10

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

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

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

Ответ 11

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

Команда

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

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

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

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

Ответ 12

Ответ 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, поэтому я его отредактировал. Некоторые люди отклонили издание, в котором мне хотелось ответить на вопрос, а не редактировать его, но я думаю, что в этом случае это много проще, практично и понятно редактировать существующий код, просто исправляя небольшую ошибку, чем писать полный ответ copy/paste/modify.) В любом случае, спасибо JonSpencer за ваш ответ, это было действительно полезно для меня!