• 締切済み

シェルのプログラム

以下の項目を実現するプログラムを作っています。 コマンドプロンプトを表示し、キーボードからコマンドを文字列として入力する。入力した文字列を調べ、forkして子プロセスを作る子プロセスで、調べたコマンドをexecする、親プロセスは子プロセスの終了を待って、始めに戻るというプログラムです。自分なりにあれこれ作ったのが下のです。 #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> void read_command(char *command, char *p) { static char buf[100]; fgets(buf, 100, stdin); sscanf(buf, "%s %[\n]", command,p); } int main(void) { pid_t pid; int status; char command[100], p[100]; while (1) { printf("command>"); read_command(command, p); pid = fork(); if (pid < 0) { printf("forkできません\n"); continue; } if (pid != 0) { wait(&status); } else { execve(command, p, 0); } } return 0; } 子プロセスと親プロセスでのforkの仕方が分かりません。 実行したら下のような結果になるようにしたいのですが、できません。 どなたか、教えてください。 $./sh command> ls a.out ・・・・・・

みんなの回答

  • trapezium
  • ベストアンサー率62% (276/442)
回答No.2

>execve(command, p, 0); execve()の第二引数はchar *argv[]の形式でなければなりません。その形式にpを加工するか、とりあえずはexeclp()を使うようにするかです。 それに実行に失敗した場合を考慮して、execのあとにexit()をおかなければなりません。 if (0 == pid) { /* child */ if (execlp(command, command, p, NULL) == -1) perror(command); exit(1); } else { /* parent */

回答No.1

fork() の結果が0なら子プロセス、非0(子プロセスのID)なら親プロセスなので: pid_t child_id = fork(); if ( child_id == 0 ) {  /* 子プロセスでやること。   * exec() とか   */ } else {  /* 親プロセスでやること。   * 子プロセスの終了を待つ、とか。   */ }

参考URL:
http://www.linux.or.jp/JM/html/LDP_man-pages/man2/fork.2.html

関連するQ&A

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

    先日学校でプログラミングの課題が出たのですが、いきなり説明もなく出されたためにまったく理解ができなくて非常に困っています。 内容はシェルプログラミングでプログラムを実行しろというモノですが、まだプログラミングを始めて幼いものでして、何が何やら理解できていないというのが現状です。 詳しい内容は #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() でプログラムが正常に実行できるように改良しろ。という内容の問題です。 上記のようにプログラムを作ることまではできたのですが、その先ができません。なんとかできるようにはできないでしょうか? ぜひ時間のある方回答お願いします。

  • 子プロセスと親プロセス

    ある本を読んでいると、以下のような問いにぶち当たり、プログラムの仕方がよくわからないのです。 自分でもいろいろ調べたのですが、わからないので質問させていただきます。 自分のプロセスIDと親のプロセスIDのプロセスIDを表示するコマンドshowpidを作り、showpidを子プロセスとして10回実行するプログラムを作りなさい。ただし、execを用いてshowpidを10回実行すること。 というものなのですが、自分のプロセスIDと親のプロセスIDの表示方法はわかったのですが、それをコマンドとして作り、子プロセスとして10回実行する方法がわからなくて困っております。。。 言語はc言語を使ってもらいたいです。以下に自分のプロセスIDと親のプロセスIDを表示するプログラムを付けときます。 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main(){ pid_t pid; int status; if((pid=fork())==0) printf("I am a child with pid=%d. My parent pid is %d.\n",getpid(),getppid()); else{ wait(&status); exit(EXIT_SUCCESS); }

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

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

    よく単純なシェルとして紹介されている下記のようなプログラム 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);はそんな意味なのでしょうか。 教えてください。

  • パイプのプログラム

    ここまでプログラムはできているのですが、親プロセスと子プロセスのところが分かりません。どなたかお願いします! XXX%a.out a|b のように入力して、コマンドaとコマンドbを、並列処理するプログラムを作っています。 なお、コマンドの実行は execl("/bin/コマンド名",コマンド名,NULL) というシステムコールを利用します。 パイプの生成およびファイル記述子の複製は、 pipe(pipefd)、 dup(pipefd[0])またはdup(pipefd[1]) のシステムコールを用います。 プログラム #include<stdio.h> #include<string.h> main(int argc,char *argv[]) { int pipefd[2],pid; char cmd_a[20]="/bin/"; if(pipe(pipefd)==-1) { perror("pipe error"); exit(1); } if((pid=fork())==-1){ perror("fork error"); exit(1); } if(pid!=0){ /*親プロセス*/ strcat(cmd_a,argv[1]); /*子プロセス*/

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

    現段階でのプログラムを載せます (質問に必要な部分を抜粋) #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; } パイプ部分が作れません・・・。 どうすればいいですか?

  • 一部コマンドでエラー

    以下のプログラムにパス検索機能を追加しろ。 /bin/lsと入力していたものを、lsだけで実行できるようにする。 そのほかにもdata -Iやgcc -o test test.c、./testを実行可能にする。 と言う課題で、 if(execv(argv[0],argv[])==(-1)){をif(execvp(argv[0],argv)==(-1)){とする方法を聞いたのですが、 gcc -o test test.cを入力すると長文のエラーが出力されます。 どうしたら良いでしょうか? #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> main(int argc, char *argv[]){ int len, pid, st; char *p; int i, sp_flag; 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'; p=(char *)&command; sp_flag=0; for(i=0; *p!='\0';p++){ if(sp_flag == 0 && *p!=' '){ argv[i]=p; sp_flag=1; i++; }else if(*p==' '){ *p='\0'; sp_flag=0; } } argv[i]=(char *)0; for(i=0; argv[i]!=(char *)0; i++){ printf("%s\n",argv[i]); } if((pid = fork()) == 0){ if(execv(argv[0],argv)==(-1)){ printf("%s", "exec error.\n"); exit(1);} } else if(pid >= 1){ wait(&st); printf("%s", prompt); } else { perror("fork"); exit(1); } } exit(0); }

  • 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を実行すればできそうだと思ったのですがうまく動かず・・・。 どうか正しく動くようなプログラムを教えてください!お願いします。

  • 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 */ というように同じファイル名が二度ずつ出力されるのです。これを出力は一度ずつにしたいのですがどのようにすればよいですか?

  • 子プロセスのデータを親プロセスに渡す方法ってありますか。

    こんにちは。 C言語内でfork()関数を使い親と子を分け、子プロセス間で生成されたデータを親プロセス側に渡して処理したいと考えています。要は、プロセス間でデータのやり取りをpipe()関数かなにかで行いたいと思っています。 子プロセスがデータをテキストファイルでどこかに出力して、それを親プロセスが参照する、というテキストファイルを橋渡しにする原始的な方法があるにはあるのですがこれは最終手段にしたいと考えています。他に良いやり方があればご教授いただけないでしょうか。 以下はサンプルコードです。 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<errno.h> #include<signal.h> #include<sys/types.h> int main(){ FILE *fp,*fp2; int fd[2],a,i = 0; pid_t pid; pipe(fd); char buff[1024]; pid = fork(); sigignore(SIGCLD); //ちゃんと子が死ぬようにする if(pid == 0){ close(STDOUT_FILENO); //画面に出力されないようにする dup2(fd[1],STDOUT_FILENO); close(fd[0]); fp = popen("tcpdump","tcpdump","tcp[13] & 255 == 2",NULL); } else{ sleep(1); //一秒だけ子プロセスを起動 kill(pid,SIGTERM); wait(); //完全に子プロセスを殺す fp2 = popen("wc -l fpのファイルデータ","r"); for(i=0;i<3;i++){ a = fgetc(fp2); putc(a,stdout); }printf("\n"); return 0; } } プログラムの内容は、 tcpdumpで処理(子プロセス)した内容を、wc -l で「行数」のみ取得する(親プロセス)というものです。あくまで目標ですが・・。^^; お手数でしょうが、どうぞよろしくお願いします。