2016-03-02 8 views
5

私はシェルを実装しています。execvp()がfork()を使って2回実行されているのはなぜですか?

ディレクトリの変更以外のコマンドを実行しようとすると、execvp()が実行されると、その子は終了し、新しい子が作成されます。ディレクトリを変更すると、子は終了せず、新しい子が作成されます。私はプログラムを終了するために二回Ctrl+Dに持っている以外

for(;;) { 
    printf("bash: "); 
    parse(); 
    ... 
    pid_t pid = fork() 
    if (pid == 0) 
     if (!strcmp(line[0], "cd")) 
      if (!line[1]) (void) chdir(getenv("HOME")); 
      else (void) chdir(line[1]); 
     else execvp(line[0], line); 
    ... 
    if (pid > 0) { 
     while (pid == wait(NULL)); 
     printf("%d terminated.\n", pid); 
    } 
} 

cd ../; ls;実行、正しく:ここに私のコードのサンプルです。

私は同じ情報(つまり、mybash < chdirtest)をパイプすると正しく1回実行され、子を終了し、元のものを除いて再び実行され、最終的な子が終了します。

+3

' execvp'を呼び出すことはありません。代わりに、 'chdir'を実行し、' fork'を呼び出す次の 'for'ループ反復を続けます。だからこそ、最初の子プロセスが 'cd'ケースのために終了しないのです。 – kaylum

+4

ようこそスタックオーバーフロー。すぐに[バージョン情報]ページをお読みください。私の直ちに取るべきことは、私たちが答えることができるほどの情報がここにないということです - 悪魔は細部にあり、細部は欠落しています。しかし、@ kaylumは問題の少なくとも一部にあり、おそらく主要な問題を特定しています。 ( 'if(pid == 0)'の後にある条件文は私には不十分であり、 'execvp()'や 'chdir()'が失敗した場合にはエラー処理は行われません)。 MCVE([MCVE])を作成してから提供します。 –

+1

@kaylum私は 'cd'が' execvp() 'を呼び出さないようにしたいと思います。ディレクトリを変更してループバックし、次に問題がなければ次の行を実行します。 –

答えて

5

cdは、子プロセスを通して呼び出されるべきではありません。シェル自体の現在のディレクトリを変更する必要があります(内部コマンドのプロパティ:シェル自体のプロセスを変更します)。

A(primitve)シェルなければならないが、次のようになります。あなたは `ショーとして(不完全)のコードを実行するとcd`

for(;;) { 
    printf("bash: "); 
    parse(); 

    // realize internal commands (here "cd") 
    if (!strcmp(line[0], "cd")) { 
     if (!line[1]) (void) chdir(getenv("HOME")); 
     else (void) chdir(line[1]); 
     continue; // jump back to read another command 
    } 

    // realize external commands 
    pid_t pid = fork() 
    if (pid == 0) { 
     execvp(line[0], line); 
     exit(EXIT_FAILURE); // wrong exec 
    } 

    // synchro on child 
    if (pid > 0) { 
     while (pid == wait(NULL)); 
     printf("%d terminated.\n", pid); 
    } 
} 
関連する問題