• ベストアンサー

execl+forkで起動したシェルの結果

execl+forkでシェルを起動したとき、 起動したシェルから返ってくる結果はどうやってとれるのでしょうか。 ============== pid_t pid_c; if(pid_c == 0) { int ret = execl(shell,shell, id, NULL); if(ret != 0) { exit(1); } } else if (pid_c < 0) { exit(1); }

noname#794
noname#794

質問者が選んだベストアンサー

  • ベストアンサー
  • mar328
  • ベストアンサー率75% (12/16)
回答No.3

質問に答え損ねてましたね。&はANDをとる演算子です。 ちょっと気になるのは、子プロのexit値が1とか2のとき 100とか200になるってことですが、使ってるマシンはなん ですか?Pentium系でしょうか?Pentium系の場合、バイト エンディアンはリトルエンディアンなので、このビット演算 のところが違うかもしれません。 エンディアンについて(ご存じかもしれませんが...) intが4バイト整数の処理系の場合、  SPARCやRISC等のビッグエンディアンの場合、ビット並びは  +-+-+-+-+  |1|2|3|4| ですが、  +-+-+-+-+  Pentiumなどの場合、  +-+-+-+-+  |4|3|2|1| となっています。  +-+-+-+-+   私の書いたビット演算とシフトは、リトルエンディアンの場合、 違ってくる(かも)しれません。 いずれにしろ、statusの4バイトのうち、どこか1バイトにexit値が 隠れているはずですから、参考になる資料が手元になければ、試しに いろいろやってみるうちに見つかるでしょう。 #なんていい加減な回答なんでしょう(^^; 他の詳しい専門家が見たら #怒られるでしょうね...。

noname#794
質問者

お礼

ありがとうございます。 さらに調べたところ、WEXITSTATUS(status)というマクロもあるみたいです。

その他の回答 (2)

  • mar328
  • ベストアンサー率75% (12/16)
回答No.2

mar328です。うまくいって何よりです。 statusの計算処理ですが、あれはビット演算を施して、int値のstatus (うちの処理系では32bit)から子プロの返すステータス値を取り出している のです。(マシンはSun Sparcで、これはビッグエンディアンマシンです。) wait(&status)で帰ってくるstatusには、いろいろな情報が入っていて、 それらはビット単位で格納されています。 (0~NビットまではXX、N+1~Mまでは○○、っていうかんじで) 細かい内容は忘れてしまい、資料も手許にないので、詳しいことが説明できない のですが、そういうことです。 (※ソースから見ると、上位から3バイト目の8ビットに格納されている値を取り 出すために0x0000ff00とマスクをかけて、それをintに格納するために8ビット 分、右へシフトしているってところでしょうか) 昔私が使っていた本で、「UNIXシステムプログラミング」という本があって、 それにはわりとわかりやすく解説がありました。 (たぶん、羽山博著、オーム社だったと...) まぁ、同じような本には載っているとは思いますが...。 こんな感じで、後は調べて見てください。 ただ、子プロセスを扱うプログラムは、親子で同期をとったり、また親子が同時に 動作しないといけないとか、いろいろ条件が複雑ですので、実際にシビアな使い方 をする場合は、よく仕様等を確認、テストしてくださいね。私も自信があまりない ので、もし不具合等のトラブルがあっても、困りますので。

  • mar328
  • ベストアンサー率75% (12/16)
回答No.1

こんにちは。ずいぶん昔にUNIXでマルチプロセスのプログラム書いた経験の あるものです。 もう当時のプログラムもCリファレンスも手許にないので...、うろ覚えで かつ、断片的な情報ですが、こんなのでも調べる何かのヒントになればと思い、 書きます。 親側で、wait()を使って子プロを待ち、調べたのではないかと思います。 確かこんな感じ... int status; wait(&status); 呼び出したプログラムのstatus値(exitの値)は、 stat = (status & 0x0000ff00) >> 8; みたいな感じで計算すれば、取得できたのでは...。 詳しくは、UNIXのシステムコールリファレンスなんかを読めば載っていると 思います。 間違えてる可能性もあるので、よく確かめてくださいね。やってみて、あってたら ラッキーってくらいに考えてください。 不確かな情報で申し訳ないです。

noname#794
質問者

補足

うまくいきました。ありがとうございます。 ところで、 stat = (status & 0x0000ff00) >> 8; って具体的に何をしてるんでしょうか。 &ってANDをとってるんでしたっけ? 戻り値が1のときstatus=100 2のときstatus=200って感じになってるのはわかったんですけど。

関連するQ&A

  • forkの失敗???

    C++(UNIX)です。 以下のようなprogramをくみました。 comは自作のCシェルです。 ------------------- : pid_t ch_pid = fork(); cout << "ch_pid = " << ch_pid<< endl; int shell_ret = 0; int execl_ret = 0; int status = 0; if( ch_pid == 0) { cout << "execl(shell)" << endl; execl_ret = execl(com, com, NULL); cout << "execl ret = " << execl_ret << endl; } else if(ch_pid < 0) { cout << "fail to fork" << endl; cout << "errno = " << errno << endl; return 0; } waitpid(ch_pid, &shell_ret, 0); : ------------------ 実行したところ、 成功する[シェルが実行される]場合と、失敗する[シェルが実行されない]場合があります。 シェルが失敗するときはそれ以上先に進まず、固まってしまいます。(waitpidのせいだと思いますが。) 成功する場合のログ --------------- ch_pid = 12885 ch_pid = 0 execl(shell) : --------------- 失敗する場合のログ --------------- ch_pid = 12885 : --------------- forkに失敗していたら、"fail to fork"と表示されると思うので forkには失敗していないと思うのですが・・・。 なぜ、execlは実行されないのでしょうか。

  • fork()のpidとppid

    システムコールのfork()の勉強をしています。 fork()によって作られたプロセスのそれぞれのpidとppidを知りたいのですが頭がこんがらがってしまいました。 「forkシステムコールは親プロセスには作成された子プロセスのプロセスIDが、子プロセスには0が返る」とあったので以下のコードの場合 pid = fork(); if(pid == 0) printf("%s, child process\n", msg); else printf("%s, parent process\n", msg); 子のpidが0のためifが実行され、親はelseが実行される というところまで理解できたのですが このとき親のpidは子のID、子のpidは0なのでしょうか? 教科書の図(添付)を見ると親のpidは0で子、孫になるにつれてpidが大きくなっていてよくわからなくなってしまいました。 例えば以下のようなコードがあった場合、 pid_t pid; // メインプロセスのPIDは42 pid = fork(); // プロセスをPID=11で作成 if (pid == 0) { pid_t pid2 = fork(); // プロセスをPID=25で作成 if (pid2 == 0) { sleep(20); exit(0); } waitpid(pid2,NULL,0); exit(0); } else { pid_t pid3 = fork(); // プロセスをPID=89で作成 if (pid3 == 0) { sleep(10); printf("** ONE **\n"); exit(0); } pid_t pid4 = fork(); // プロセスをPID=123で作成 if (pid4 == 0) { sleep(30); printf("** TWO **\n"); exit(0); } } sleep(20); exit(0); それぞれのプロセスのpidとppidはどうなるのでしょうか? 説明がうまくできないのですが、 分かる方いましたら回答よろしくお願いします。

  • C言語のシェルプログラミングの課題が分かりません。

    C言語のシェルプログラミングを作れという課題で、以下のように作ったんですが、実行して何度かコマンドを入力した後、exitによって一発で終わらせることができません。どのように書き換えればいいか教えて下さい。 また、他にも書き換えた方がよいと思えるところがあったら是非教えて下さいm(_ _)m #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #include MAX_ARGS 10 #include MAX_LEN 100 extern char **environ; void child(int argc, char *argv[MAX_ARGS]); int main(void){ int argc, n = 0; int status; char input[MAX_LEN], *argv[MAX_ARGS], *cp; const char *delim = "\t\n"; while (1){ ++n; printf("$ "); fflush(stdout); if(fgets(input, sizeof(input), stdin) == NULL){ break; } cp = input; for(argc = 0; argc < MAX_ARGS; argc++){ if((argv[argc] = strtok(cp, delim)) == NULL) break; cp = NULL; } if(strcmp(argv[0], "exit") == 0){ exit(0); } pid_t pid = fork(); if(pid == -1){ perror("fork"); exit(1); }else if(pid == 0){ child(argc, argv); }else{ wait(&status); } } return 0; } void child(int argc, char *argv[MAX_ARGS]{ execvp(argv[0], argv); }

  • forkについて

    fork文を使った問題について質問です。 #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { pid_t pid1,pid2; if((pid1 = fork()) == 0) printf("I am a first child with pid = %d,My parent pid is %d.\n",getpid(),getppid()); else if(( pid2 = fork()) == 0) printf("I am a second child with pid = %d,My parent pid is %d.\n",getpid(),getppid()); else printf("I am a parent with pid = %d.\nMy first and second children are %d and %d.\n",getpid(),pid1,pid2); exit(EXIT_SUCCESS); } このようなプログラムが与えられました。 問題は 1.このプログラムを改造して、1つの親プロセスから100の子プロセスを順に生成するプログラムをつくるというものと 2.1つの親から子プロセスを生成し、その子プロセスの孫プロセスを生成するプログラムをつくれというものです。 1はfor文を使えばできそうなのですが、forkの基礎が出来ていないのでどうループを回せばよいか分かりません。 2もfork内でforkを実行すればできそうだと思ったのですがうまく動かず・・・。 どうか正しく動くようなプログラムを教えてください!お願いします。

  • 「単純なシェル」について

    よく単純なシェルとして紹介されている下記のようなプログラム while (1) { type_prompt(); read_command(command, params); pid = fork(); if (pid < 0) { printf("Unable to fork\n"); continue; } if (pid != 0) { wait(&status); } else { execve(command, params, 0); } } これを実際にC言語のプログラムとして実行するには、このプログラムにどのような実装をくわえればよいのでしょうか。 またプログラム中のtype_prompt();とread_command(command, params);はそんな意味なのでしょうか。 教えてください。

  • プログラミングの課題でシェルプログラミングが出たのですが・・・全くわけがわからないので助言を…

    先日学校でプログラミングの課題が出たのですが、いきなり説明もなく出されたためにまったく理解ができなくて非常に困っています。 内容はシェルプログラミングでプログラムを実行しろというモノですが、まだプログラミングを始めて幼いものでして、何が何やら理解できていないというのが現状です。 詳しい内容は #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <stdlib.h> #include <string.h> main(int argc, char *argv[]) { int len, pid, st; static char prompt[64]="> "; char command[256]; printf("%s",prompt); while (fgets(command, 256, stdin) != NULL){ if ((len = strlen(command)) == 1) break; command[len-1] = '\0'; if((pid = fork()) == 0) { if (execl(command,command,(char *)0)==(-1)){ printf("%s", "exec error.\n"); exit(1); } } else if(pid >= 1) { wait(&st); printf("%s", prompt); } else { perror("fork"); exit(1); } } exit(0); } というプログラム(自作なのであってるかは…)なのですが、これにはコマンドに引数があると、exec() でエラーになるという欠点があります。また、パス検索機能も指定されていないので、コマンドはフルパスで入力してあります。そこで問題なのですが、パス検索機能を追加するとともに、コマンドに引数があっても、exec() でプログラムが正常に実行できるように改良しろ。という内容の問題です。 上記のようにプログラムを作ることまではできたのですが、その先ができません。なんとかできるようにはできないでしょうか? ぜひ時間のある方回答お願いします。

  • forkで子が親を終了させるか?

    fork() によって作られた子プロセスが、親プロセスを終了させる場合があるでしょうか? 形としては良く見かけるもので次のようになっています。 pid_t pid = fork(); if (pid < 0) {  エラー処理  return; } else if (pid == 0) {  子の処理 ... (1)  _exit(0); } /* ここが実行されない場合がある */ return; (1)の箇所に sleep() を幾らか入れると再現しなくなります。 親子の関係で子が親へ影響を与えることがあるでしょうか?

  • シェルでのパイプの処理の書き方で困ってます

    現段階でのプログラムを載せます (質問に必要な部分を抜粋) #include "自作のヘッダファイル(動作確認済)" void tokun ( char str[], char *chops[], int *flagment , int *pipeflagment, int *pipe, int *num){ char *buf; int i; *pipeflagment = 0; buf = str; for(i=0; i <= SIZE ; i++){ if((chops[i] = strtok(buf," \t")) == NULL) break; if( *chops[i] == '|' ){ *pipeflagment = 1; *pipe = i + 1; *num = i; } buf = NULL; } if( *chops[i-1] == '&' ){ *flagment = BACK; chops[i-1] = NULL; i--; printf("**Background Mode**\n"); }else{ *flagment = FORE; printf("**Foreground Mode**\n"); } if(i > SIZE){ fprintf(stderr,"Too many args\n"); exit(1); } } int main ( void ){ char prompt[ 64 ] = "> "; char command[ 256 ]; int st, id, j, pipenum, num; char *com[256]; enum proc_flag flag; int pipeflag ; int out; int pipe_fd[2]; int child, status; char *buf; pipeflag = 0; fprintf(stderr, "%s", prompt); while (gets(command) != NULL){ if( command == "quit" ){ kill(0, SIGKILL); } buf = command; tokun(command, com, &flag, &pipeflag, &pipenum, &num); //pipe部分の記述開始 if( pipeflag == 1){ com[num] = NULL; if(pipe(pipe_fd) < 0){ perror("pipe"); exit(1); } if((child = fork()) < 0){ perror("fork"); exit(1); } if(child) { /* parent process */ close(pipe_fd[1]); dup2(pipe_fd[0], STDIN); execvp (com[pipenum], com); close(pipe_fd[0]); if(wait(&status) < 0){ perror("wait"); exit(1); } }else { /* child process */ close(pipe_fd[0]); dup2(pipe_fd[1], STDOUT); execvp (com[0], com); // 通信の終了を子プロセスに通知 close(pipe_fd[1]); } } //pipe部分の記述終了 if((id = fork ()) == 0){ if( execvp(com[0], com) == (-1)){ exit(1); } }else { if( flag == BACK ){ waitpid(-1, NULL, WNOHANG); fprintf(stderr, "%s", prompt); }else { wait(&st); fprintf(stderr, "%s", prompt); } } } return 0; } パイプ部分が作れません・・・。 どうすればいいですか?

  • forkでプリント結果の違い

    文末改行無しの動きがわかりません $pid = fork; if($pid){ Pid(1); wait; }else{ Pid(2); } sub Pid{ print"#$_[0]\n&"; #print"#$_[0]\n&\n"; }

    • ベストアンサー
    • Perl
  • ls | sort を実行するプログラム

    以下のプログラムはls | sortを実行するプログラムなのですが、出力が2回ずつ出てしまい困っております。以下に実行結果も載せましたので参照ください。 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> main(int argc,char **argv){ int a[2],b[2]; int cint,status; char n; pid_t pid1,pid2; if(pipe(a)==-1){ perror("pipe"); exit(EXIT_FAILURE); } if(pipe(b)==-1){ perror("pipe"); exit(EXIT_FAILURE); } if((pid1 = fork())==-1){ perror("fork"); exit(EXIT_FAILURE); } if((pid2 = fork())==-1){ perror("fork"); exit(EXIT_FAILURE); } //子1 else if(pid1==0){ close(a[0]); close(b[0]); close(b[1]); dup2(a[1],1); close(a[1]); execlp(argv[1],argv[1],(char *)0); } //子2 else if(pid2==0){ close(a[1]); close(b[0]); dup2(a[0],0); dup2(b[1],1); close(a[0]); close(b[1]); execlp(argv[2],argv[2],(char *)0); } //親 else { close(a[0]); close(a[1]); close(b[1]); wait(&status); while((read(b[0],&n,1))==1){ putchar(n); } close(a[0]); } exit(EXIT_SUCCESS); } /*実行結果 $ ./pipesort ls sort 2^31-1.c~ 2^31-1.c~ a*b.c~ a*b.c~ a-z.c a-z.c a-z.c~ a-z.c~ a-z1.c a-z1.c a-z1.c~ a-z1.c~ a.c a.c a.c~ a.c~ a.out a.out a.sp~ a.sp~ a10 a10 */ というように同じファイル名が二度ずつ出力されるのです。これを出力は一度ずつにしたいのですがどのようにすればよいですか?