web-dev-qa-db-ja.com

Linuxの「システム」と「exec」の違いは?

systemexecファミリコマンドの違いは何ですか?特に、どれが動作する子プロセスを作成するかを知りたいですか?

67
Kamil

system()は、コマンドラインを処理するためにshを呼び出すため、ワイルドカード拡張などを取得できます。exec()とその友人は、現在のプロセスイメージを新しいプロセスに置き換えます。画像。

system()を使用すると、プログラムの実行が継続され、呼び出した外部コマンドに関するステータスが返されます。 exec()を使用すると、プロセスは消去されます。

一般に、system()をより高レベルのインターフェイスと考えることができると思います。 fork()exec()、およびwait()の組み合わせを使用して、その機能を自分で複製できます。

最後の質問に答えるために、system()は子プロセスを作成しますが、exec()ファミリは作成しません。そのためにはfork()を使用する必要があります。

89
Carl Norum

Exec関数は、成功すると現在実行中のプロセスイメージを置き換え、子は作成されません(以前にfork()を使用して自分で行った場合を除きます)。 system()関数は子プロセスをフォークし、指定されたコマンドの実行が終了するかエラーが発生すると戻ります。

19
BobbyShaftoe

system()は、生成された子プロセスで提供されたコマンドを実行します。 exec()は、現在のプロセスを、指定した新しい実行可能ファイルの呼び出しに置き換えます。 execを使用して子プロセスを生成する場合は、事前にプロセスをfork()する必要があります。

7
Timo Geusch

プロセスを作成するには:

  • fork(2)、カーネルへの直接のシステムコール

プログラムを実行するには、現在のイメージを置き換えます:

  • execve(2)、カーネルへの直接のシステム呼び出し、通常は単にexecと呼ばれます

子プロセスの終了を待つには:

  • wait(2)、カーネルへの直接のシステムコール

子プロセスのシェルでプログラムを実行し、終了するのを待つには:

  • system(3)、ライブラリ関数

上記のすべてについて manページ を取得するには:

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

system()は、システムのデフォルトコマンドシェルを呼び出します。シェルは、引数として渡されたコマンド文字列を実行します。シェルは、コマンドとシステムに依存するプロセスを作成する場合としない場合があります。いずれにしても、少なくともコマンドシェルプロセスが作成されます。

System()では任意のコマンドを呼び出すことができますが、exec()では実行可能ファイルのみを呼び出すことができます。シェルスクリプトとバッチファイルは、シェルコマンドで実行する必要があります。

基本的に、それらは異なる目的に使用されるまったく異なるものです。さらに、exec()は呼び出しプロセスを置き換え、戻りません。より便利な比較は、system()とspawn()の比較です。システムの呼び出しは簡単かもしれませんが、コマンドシェルが呼び出されたかどうかを示す値を返し、コマンド自体の成功については何も通知しません。 spawn()を使用すると、プロセスの終了コードを取得できます。慣例により、非ゼロはエラー状態を示すために使用されます。 exec()と同様に、spawn()は、シェルスクリプトや組み込みコマンドではなく、実行可能ファイルを呼び出す必要があります。

2
Clifford

_int system(const char *cmdstring);
_

例:system("date > file");


一般的に、システムfork、exec、およびwaitpidを呼び出すことで実装されます。戻り値には3つのタイプがあります。

  • Forkが失敗するか、waitpidがEINTR以外のエラーを返す場合、システムは-1を返し、エラーを示すerrnoを設定します。
  • Execが失敗し、シェルを実行できないことを意味する場合、戻り値はシェルがexit(127)を実行したかのようになります。
  • それ以外の場合、3つの関数(fork、exec、およびwaitpid)はすべて成功し、システムからの戻り値は、waitpidに指定された形式のシェルの終了ステータスです。

fork関数は、exec関数の1つを呼び出して別のプログラムを実行させる新しいプロセス(子)を作成します。プロセスがexec関数の1つを呼び出すと、そのプロセスは新しいプログラムに完全に置き換えられ、新しいプログラムはメイン関数で実行を開始します。新しいプロセスは作成されないため、プロセスIDはEXEC全体で変更されません。 execは、現在のプロセス(テキスト、データ、ヒープ、およびスタックセグメント)をディスクからのまったく新しいプログラムに置き換えるだけです。

6つの異なる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()は戻りコードを提供しますが、戻りコードはエラー状態の検出にのみ使用でき、戻りコードの回復には使用できません。

システムコールの適切なシーケンスの1つは次のとおりです。

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

このシーケンスには他にも微妙な点がありますが、関連するマニュアルページを注意深く読むことで判断できますが、このコードはシグナル、複数の子プロセスなどがない場合でも問題なく動作します。また、インライン宣言はただし、このコードを機能するテンプレートとして使用できるようにするために含まれています(別のコーディングスタイルを使用することもできます:-)。

1
Jon Spencer

exec()は、現在実行中のプロセスを、実行中の関数のプロセスイメージに置き換えます。これを使用して実行可能ファイルのみを呼び出すことができます。

system()は、要求を処理するために暗黙的に新しいプロセスをフォークし、最初にフォークした子プロセスから取得した値を返します。システムのデフォルトのシェルを使用して操作を実行します。

1
Morpheus

system()は、シェルを使用して目的のプログラムまたは組み込みコマンドを呼び出します。これは、プログラムが開始される前にシェルが開始されるため、非効率的な方法です。

システムコールのexecファミリの場合、まったく新しいイメージが作成されます。つまり、現在のプロセスが、パスまたはファイル、または言及している引数で指定された新しいプロセスに置き換えられます。

心に留めておくべきことは、システムコールのexecファミリを使用すると、新しいプログラムが開始された後に元のプログラムが実行されなくなることです。

0
kishanp

System()は子プロセスを作成し、別のサブシェルを呼び出しますが、exec()は子プロセスを作成しません。

いくつかのコード...

exec( 'ls -l')

echo "1 2 3" //これはbashで実行されません(execコマンドは同じシェルを使用するため)

いくつかのコード...

system(ls -l)echo "1 2 3" //これは、システムの子プロセスが終了した後に実行されます。親PIDとは異なるためです。

0
Poseidon_Geek

一般に、「システム」は非常に効率が悪いため、小さなコードがない限り使用しないでください。プロセスで複数のプログラムを実行する必要がある場合、fork&execを使用する方がより複雑になります。それらの違いのリストは次のとおりです。

1-「システム」コマンドは、プログラムを実行するシェルのコピーを作成します。システムを呼び出すたびに、シェルのコピーを作成します。したがって、プロセス内で実行するプログラムが多数ある場合は使用しないでください。

2-具体的には、「mv」、「mkdir」などのシステム関数を実行する場合は、「system(」で実行するのではなく、mkdir()、unlink()、remove()などのルーチンを使用することをお勧めしますrm .... ")またはsystem(" mkdir .... ")"。

3-システムがシェルを呼び出して目的のプログラムを実行するため、ユーザーのアクセス許可に問題がある可能性があります。たとえば、誰かがあなたのコードを解読し、システムコマンドを介して実行する予定のプログラムの代わりに別の何かを実行する可能性があります。

詳細については、この本の第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
        }
     }
  }
}

(私はまだJonの投稿にコメントするほどの評判がないので編集したことを指摘してください。編集する代わりに質問に答えるように頼む版を拒否した人もいますが、この場合はもっと簡単で実用的だと思います。完全なコピー/貼り付け/修正の回答を書くよりも、小さな間違いを修正するだけで既存のコードを編集することを明確にしています。とにかく、JonSpencerの回答に感謝します。本当に役に立ちました!

0
jap jap