execは、C言語で別プログラムを実行(execute)する関数。
|
|
|
exec系の関数は、別プログラムを実行する。
「exec」という関数そのものは無くて、execl・execv・execvp等のいくつかのバリエーションがある。
exec系関数によって別プログラムを実行すると、制御はそのプログラムへ移行し、自プログラムへは戻ってこない。(execの実行に失敗した場合だけ戻ってくる)
自分の処理を続行したい場合はfork()と組み合わせて使用する。
→forkと組み合わせる例
別プロセスを実行する方法は、execの他にもsystem(シェルの機能を使ってコマンドを実行する)やpopen(パイプで通信可)等がある。
execl(exec「L」)は引数が可変長引数になっていて、execv(exec「v」)は引数が配列になっている。
execlpやexecvp(「p」が付いた関数)は、実行するプログラムにファイル名のみを指定した場合は環境変数PATHで指定された場所から該当プログラムを探す。
(普通は、実行するプログラムを絶対パスで指定する)
execleやexecvpe(「e」が付いた関数)は、環境変数を渡したい場合に使用する。
「/bin/echo」を実行してみる例。
#include <unistd.h>
int main() { execl("/bin/echo", "/bin/echo", "abc", "def", NULL); //制御が戻ってくるのは、エラーが発生した場合のみ perror("/bin/echo"); return -1; }
int main() { char *const args[] = { "/bin/echo", "abc", "def", NULL, //C99では末尾にカンマがあってもOK! }; execvp(args[0], args); //制御が戻ってくるのは、エラーが発生した場合のみ perror(args[0]); return -1; }
第1引数に実行するプログラムのパス(あるいはファイル名)を指定する。
第2引数以降はそのプログラムへの実行時引数(main()のargvと同様の形式)を記述する。
execlとexecvでは書き方は違うが、内容は同じ。すなわち、先頭がコマンド、それ以降が引数で、最後には必ずNULLを入れる。
これは、main(int argc, char *argv[])が受け取るargvと全く同じ。
C言語で実行時引数全てを処理するときはargcで判定してループするのが一般的だが、実はargvの最後にはNULLが入っているので、argvだけでループできる。
argcを使用した例 argvのみの例 int main(int argc, char *argv[]) { int i; for (i = 0; i < argc; i++) { printf("%s\n", argv[i]); } } int main(int argc, char *argv[]) { char **p; for(p = argv; *p != NULL; p++) { printf("%s\n", *p); } }
プログラムの戻り値は、execによって実行したプログラムの戻り値になる。
$ gcc exec1.c -o exec1.out $ ./exec1.out abc def
実行対象のファイル(プログラム)が見つからない場合はエラーになる。
$ ./exec1.out
/bin/echo1: No shch file or directory
※これは、perror()によって表示されるメッセージ。コロン「:
」の左側がperror()に渡した引数、右側がエラー内容。
exec系関数は制御が戻ってこない為、自分の処理を続行させたい場合はfork()によって子プロセスを生成し、そこでexecを実行するのが常套手段。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h>
int main() { pid_t pid = fork(); if (pid < 0) { perror("fork"); exit(-1); } else if (pid == 0) { // 子プロセスで別プログラムを実行 execlp("echo", "echo", "abc", "def", NULL); perror("echo"); exit(-1); } // 親プロセス int status; pid_t r = waitpid(pid, &status, 0); //子プロセスの終了待ち if (r < 0) { perror("waitpid"); exit(-1); } if (WIFEXITED(status)) { // 子プロセスが正常終了の場合 printf("child exit-code=%d\n", WEXITSTATUS(status)); } else { printf("child status=%04x\n", status); } return 0; }