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