2017-03-26 17 views
3

は、私は、配管やFDSをリダイレクトする原理を理解していました。しかし、パイプでの特定の動作が私の注目を集めています:パイプは、私は現在、C言語で自分の殻の実装を書いています

  • cat | ls(またはstdinからパイプの最後の要素として読み取られないコマンド)。

その場合、シェルではlsが実行され、catは終了する前に(私が推測したSIGPIPEの結果で)1行を要求します。

char *cmd1[] = {"/bin/cat", NULL}; 
char *cmd2[] = {"/bin/ls", NULL}; 
int  pdes[2]; 
pid_t child; 

if (!(child = fork())) 
{ 
    pipe(pdes); 
    if (!fork()) 
    { 
     close(pdes[0]); 
     dup2(pdes[1], STDOUT_FILENO); 
     /* cat command gets executed here */ 
     execvp(cmd1[0], cmd1); 
    } 
    else 
    { 
     close(pdes[1]); 
     dup2(pdes[0], STDIN_FILENO); 
     /* ls command gets executed here */ 
     execvp(cmd2[0], cmd2); 
    } 
} 
wait(NULL); 

私が知っ:以下

http://web.cse.ohio-state.edu/~mamrak.1/CIS762/pipes_lab_notes.htmlは私が探しています振る舞いを再現しようとするために書かれているいくつかのコードです:私はより良い複数のパイプの原理を理解するために、このチュートリアルに従うことを試してみましたその実装のセキュリティ上の欠陥ですが、これはテスト用です。私はそれを理解するように、そのコードの問題は、LSが実行されますいつでも、それだけで終了し、その後、猫が何らかの形で、バックグラウンドで実行されることである(そして、それは私のプログラムが終了するなどのzshのプロンプト時に読み取ろうとするので、私の場合には失敗します)。私はそれがそうであるようにそれを働かせるための解決策を見つけることができません。コマンドを1つずつ待つと、そのようなコマンドはcat/dev/random |となります。誰もがこの問題の解決や、それが非常に高く評価されるだろう、少なくともいくつかのガイダンスを持っている場合はヘッド-c 10は...永遠

を実行します。ここ@thatotherguyからのコメントを考慮した後

+0

私は全くコマンド有用性に興味を持っていないです。私はあるbashの動作を複製するにしか興味午前: 'cat'は'ながら孫になり、あなたの例では最初のlsの出力を表示し、(1ライン分のユーザを促しすなわち)1つだけの行を取る猫を実行している –

+2

lsは子供です。 'wait'は' ls'を待つだけです。代わりに 'cat'と' ls'の両方の子を直接作成し、両方を待つべきです。 –

+0

@thatotherguyはい確かに私はあなたのソリューションを実験しましたが、それは間違いなく機能します。そして、このソリューションは、私がリンクしているチュートリアルで提供されている最初のアイデアに近いようです。しかし、複数のコマンドでこれを拡張したい場合はどうなりますか?それが2番目の実装が私にとってもっと興味深いように見える理由です!私は多くの連鎖コマンドを持つことができるはずです。その解決策では、私はパイプやフォークを準備するためにどれだけのコマンドを事前に知っていなければならないようです。 –

答えて

0

は私のコードで実装として私が見つけた解決策です。 パイプフォーク呼び出しがエラーをチェックする必要がありますが、このバージョンは、できるだけ簡単であることを意味していることを心に留めておいてください。余分な出口私の組み込みコマンドのいくつかの呼び出しも必要です。

void exec_pipe(t_ast *tree, t_sh *sh) 
{ 
    int  pdes[2]; 
    int  status; 
    pid_t child_right; 
    pid_t child_left; 

    pipe(pdes); 
    if (!(child_left = fork())) 
    { 
     close(pdes[READ_END]); 
     dup2(pdes[WRITE_END], STDOUT_FILENO); 
     /* Execute command to the left of the tree */ 
     exit(execute_cmd(tree->left, sh)); 
    } 
    if (!(child_right = fork())) 
    { 
     close(pdes[WRITE_END]); 
     dup2(pdes[READ_END], STDIN_FILENO); 
     /* Recursive call or execution of last command */ 
     if (tree->right->type == PIPE_NODE) 
      exec_pipe(tree->right, sh); 
     else 
      exit(execute_cmd(tree->right, sh)); 
    } 
    /* Should not forget to close both ends of the pipe */ 
    close(pdes[WRITE_END]); 
    close(pdes[READ_END]); 
    wait(NULL); 
    waitpid(child_right, &status, 0); 
    exit(get_status(status)); 
} 

私が投稿した元のリンクとチェーンされたパイプを扱うさまざまな方法とは混同していました。私の元の質問の下に掲示文書POSIXへのリンクから(http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_02)は、その表示されます:パイプラインがバックグラウンドではありません

場合は、シェルがで指定された最後のコマンドを待つものとし、(非同期リストを参照してください)すべてのコマンドが完了するのを待つことがあります。

したがって、最後のコマンドを待っているか、それらのすべてを待っているというふうに両方の動作が受け入れられます。私は、bash/zshが行うことに固執する第2の動作を実装することを選択しました。

関連する問題