web-dev-qa-db-ja.com

Bashでパイプがどのように機能するかについての簡単な説明は何ですか?

私はよくBashでパイプを使用します、例えば:

dmesg | less

これが何を出力するかは知っていますが、dmesgを取り、lessでスクロールさせます。|が何をしているのかわかりません。それは単に>の反対ですか?

  • |の機能について簡単な、または比simple的な説明はありますか?
  • 単一のラインで複数のパイプを使用するとどうなりますか?
  • パイプの動作は、Bashスクリプトに表示されるすべての場所で一貫していますか?
55
Village

Unixパイプは、最初のプロセスのSTDOUT(標準出力)ファイル記述子を2番目のプロセスのSTDIN(標準入力)に接続します。その場合、最初のプロセスがそのSTDOUTに書き込むと、その出力は2番目のプロセスによって(STDINから)すぐに読み取られます。

複数のパイプを使用することは、単一のパイプを使用することと同じです。各パイプは独立しており、隣接するプロセスのSTDOUTとSTDINを単純にリンクします。

3番目の質問は少しあいまいです。はい、パイプ自体は、bashスクリプトのどこでも一貫しています。ただし、パイプ文字|はさまざまなものを表すことができます。ダブルパイプ(||)は、たとえば「or」演算子を表します。

68
quanticle

Linux(および一般的なUnix)では、各プロセスには3つのデフォルトのファイル記述子があります。

  1. fd#0プロセスの標準入力を表します
  2. fd#1プロセスの標準出力を表します
  3. fd#2プロセスの標準エラー出力を表します

通常、単純なプログラムを実行すると、これらのファイル記述子はデフォルトで次のように構成されます。

  1. デフォルトの入力はキーボードから読み取られます
  2. 標準出力はモニターとして構成されます
  3. 標準エラーもモニターになるように構成されています

Bashには、この動作を変更するための演算子がいくつか用意されています(たとえば、>、>>、<演算子を見てください)。したがって、出力を標準出力以外にリダイレクトしたり、キーボードとは異なる他のストリームから入力を読み取ったりできます。特に興味深いのは、2つのプログラムがcollaboratingで、一方が他方の出力を入力として使用する場合です。このコラボレーションを簡単にするために、Bashはパイプ演算子|chainingの代わりにコラボレーションを使用することに注意してください。実際、パイプはシーケンシャルではないため、この用語の使用を避けました。パイプを使用した通常のコマンドラインには、次の側面があります。

    > program_1 | program_2 | ... | program_n

上記のコマンドラインは少し誤解を招く可能性があります。ユーザーは、program_1の実行が終了すると、program_2が入力を取得すると考えることができますが、これは正しくありません。実際、bashは[〜#〜] all [〜#〜]プログラムを並行して起動し、それに応じて入力出力を構成します。すべてのプログラムは、前のプログラムから入力を取得し、次のプログラムに出力を配信します(コマンドラインで確立された順序で)。

以下は、親プロセスと子プロセスの間にパイプを作成する Cでパイプを作成する の簡単な例です。重要な部分は、pipe()の呼び出しと、親がfd 1 (書き込み側)を閉じる方法と、子がfd 1 (書き込み側)を閉じる方法です。パイプは単方向通信チャネルであることに注意してください。したがって、データは一方向にしか流れることができません:fd 1 fd [0]に向かって。詳細については、pipe()のマニュアルページを参照してください。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void)
{
    int     fd[2], nbytes;
    pid_t   childpid;
    char    string[] = "Hello, world!\n";
    char    readbuffer[80];

    pipe(fd);

    if((childpid = fork()) == -1)
    {
            perror("fork");
            exit(1);
    }

    if(childpid == 0)
    {
            /* Child process closes up input side of pipe */
            close(fd[0]);

            /* Send "string" through the output side of pipe */
            write(fd[1], string, (strlen(string)+1));
            exit(0);
    }
    else
    {
            /* Parent process closes up output side of pipe */
            close(fd[1]);

            /* Read in a string from the pipe */
            nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
            printf("Received string: %s", readbuffer);
    }

    return(0);
}

最後になりましたが、次の形式のコマンドラインがある場合:

> program_1 | program_2 | program_3

行全体の戻りコードは、lastコマンドに設定されます。この場合、program_3。中間戻りコードを取得したい場合は、pipefailを設定するか、[〜 #〜] pipestatus [〜#〜]

20
rkachach

Unixのすべての標準プロセスには、少なくとも3つのファイル記述子があり、これらはinterfacesのようなものです。

  • 標準出力。プロセスがデータを印刷する場所です(ほとんどの場合、コンソール、つまり画面または端末)。
  • 標準入力。データを取得する場所です(ほとんどの場合、キーボードに似ている場合があります)。
  • 標準エラー。エラーおよび場合によってはその他の帯域外データが送信される場所です。パイプは通常それを処理しないので、今は面白くありません。

パイプ接続左側のプロセスの標準出力から右側のプロセスの標準入力へ。これは、1つのプログラムが印刷するすべてをコピーして、次のプログラム(パイプ記号の後のプログラム)に供給する専用のプログラムと考えることができます。それは正確にそれではありませんが、それは十分に十分な類推です。

各パイプは、正確に2つのことで動作します。左から来る標準出力と右で期待される入力ストリームです。これらはそれぞれ、単一プロセスまたはパイプラインの別のビットに接続できます。これは、マルチパイプコマンドラインの場合です。しかし、それはパイプの実際の操作には関係ありません。各パイプは独自の処理を行います。

リダイレクション演算子(>)は何か関連することを行いますが、より簡単です:デフォルトでは、プロセスの標準出力を直接ファイルに送信します。ご覧のとおり、パイプの反対ではありませんが、実際には相補的です。 >の反対は、当然のことながら<です。これは、ファイルの内容を取得し、プロセスの標準入力に送信します(ファイルをバイト単位で読み取り、入力するプログラムと考えてください)あなたのためのプロセスで)。

15
Eduardo Ivanec

パイプはプロセスの出力を受け取ります。出力とは、標準出力(UNIXではstdout)を意味し、別のプロセスの標準入力(stdin)に渡します。出力を別の出力にリダイレクトすることを目的とする単純な右リダイレクト>の反対ではありません。

たとえば、Linuxでechoコマンドを実行すると、パラメーターで渡された文字列が標準出力に出力されます。次のような単純なリダイレクトを使用する場合:

echo "Hello world" > helloworld.txt

シェルは、最初は標準出力にあることを意図した通常の出力をリダイレクトし、ファイルhelloworld.txtに直接出力します。

さて、パイプを含むこの例を見てください:

ls -l | grep helloworld.txt

lsコマンドの標準出力はgrepのエントリで出力されますが、これはどのように機能しますか?

引数なしで使用されているgrepなどのプログラムは、単に標準入力(stdin)で何かが渡されるのを読んで待っています。 lsコマンドの出力のように、何かをキャッチすると、grepは通常、検索対象の出現を検出して動作します。

6
Halim Qarroum

パイプ演算子は、最初のコマンドの出力を取得し、stdinとstdoutを接続することにより、2番目のコマンドに「パイプ」します。あなたの例では、dmesgコマンドの出力がstdoutに行く(そしてコンソールでそれを捨てる)のではなく、次のコマンドに直接入っています。

2
franka

パイプはこのように非常に単純です。

1つのコマンドの出力があります。パイプを使用して、この出力を別のコマンドへの入力として提供できます。必要な数のコマンドをパイプできます。

例:ls | grep my | grepファイル

これは最初に作業ディレクトリ内のファイルをリストします。この出力は、単語「my」のgrepコマンドによってチェックされます。この出力は、最後にWordの「ファイル」を検索する2番目のgrepコマンドに出力されます。それでおしまい。

2
Xander
  • |は、コマンドのSTDOUTを左側のコマンドのSTDINに配置します。

  • 複数のパイプを使用する場合、それは単なるパイプのチェーンです。最初のコマンド出力は、2番目のコマンド入力に設定されます。 2番目のコマンド出力は、次のコマンド入力に設定されます。などなど。

  • すべてのLinux/widowsベースのコマンドインタープリターで使用できます。

2
Shiplu Mokaddim

各UNIXコマンドをスタンドアロンモジュールとして扱う場合、
しかし、あなたはconsistentインターフェースとしてテキストを使用してお互いに話す必要があります
どうすればできますか?

cmd                       input                    output

echo "foobar"             string                   "foobar" 
cat "somefile.txt"        file                     *string inside the file*
grep "pattern" "a.txt"    pattern, input file      *matched string*

|はリレーマラソンでバトンを渡すための比phorであると言えます。
1個の形も!
cat -> echo -> less -> awk -> Perlcat | echo | less | awk | Perlに類似しています。

cat "somefile.txt" | echo
catは使用するechoの出力を渡します。

複数の入力があるとどうなりますか?
cat "somefile.txt" | grep "pattern"
grepにはpattern "ではなくinput fileとして渡す」という暗黙のルールがあります。
経験により、どのパラメーターがどのパラメーターであるかを知るための目をゆっくりと発達させます。

1
cctan