1つのコマンドの出力を複数のコマンドに渡すにはどうすればよいですか?


20

プロセス置換を使用するか、グループ化およびパイピングにより、出力(stdout)に一連のコマンドを別のコマンドの入力として渡すことができます。

例:

wc < <(echo hi;echo bye)
(echo hi; bye) | wc

しかし、反対はありますか?

つまり、他の多くのコマンドの入力として1つのコマンドの出力を送信する方法がある単一のラインは

何かのようなもの :

cat testfile | wc | tail -n 5

文字通りパイプラインを使わないでください)。ここで私はの出力パスしようとしているcat testfileの両方にをwcし、tail -n 5

別の例は次のとおりです。

文の最後の単語を取得するには

echo "some random words"| wc -c | cut -f(out put of wc -c) (output of first echo)

回答:


21

素早い回答。を使用tee >(what_to_do) >(another_thing_to_do)して、実行したいさまざまなことに対してコマンドを実行し続けることができます。

例:

元のテストファイル出力:

:~$ cat testfile.txt 
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616

teeコマンドが追加された出力:

:~$ cat testfile.txt | tee >(tail -1) >(wc) >(awk '{print $3,$1,$2}')
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616
LITEONIT Device Model:
TW0XFJWX550854187616 Serial Number:
      2      10      91
Serial Number:    TW0XFJWX550854187616

teeの各コマンドは、add in >(head -1 | wc)worksのように、コマンドラインで使用する通常のコマンドです。

:~$ cat testfile.txt | tee >(tail -1) >(head -1 | wc)  >(awk '{print $3,$1,$2}')
Device Model:     LITEONIT LCS-256M6S 2.5 7mm 256GB
Serial Number:    TW0XFJWX550854187616
      1       7      52
LITEONIT Device Model:
TW0XFJWX550854187616 Serial Number:
Serial Number:    TW0XFJWX550854187616

または、awkwith $NFを次のwcように使用して、最後の行の最後の単語を取得することもできます。

:~$ cat testfile.txt | tail -1 | tee >(wc) >(awk '{print $NF}')
Serial Number:    TW0XFJWX550854187616
TW0XFJWX550854187616
      1       3      39

注:|パイプコマンドを最後に追加すると、コマンドから複数のコマンドを使用してオーバーライドできますtee。私がテストしてきたいくつかの例があります:

例1(すべての最後の単語を引くパイプコマンド):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) | awk '{print $NF}'
words
24
5
1

例2(wcコマンドの出力を表示しません。3番目のワードを取得するパイプコマンド。):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) | awk '{print $3}'
just

例3(エコー行の3番目のワードを取得します。Teeコマンド。):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) >(awk '{print $3}')
This is just five words
just
24
5
1

例4(エコー行の最後の単語を取得します。Teeコマンド。):

:~$ echo "This is just five words" | tee >(wc -l) >(wc -w) >(wc -c) >(awk '{print $NF}')
This is just five words
words
24
5
1

お役に立てれば!


3
ティーとコーヒーが大好き!'-)
オタク長老

1
のさまざまなコンシューマー間の出力の順序に関するステートメントteeはfalseです。通常正しい順序を取得する理由は、低負荷マシンでは、最初のコンシューマプロセスが最初に実行されるためです。忙しいマシンでは、最初の消費者が何かを印刷する前にスリープ状態になる可能性があります。
マテイデビッド

@MateiDavidそれ以外の場合は証明できないので、ステートメントを削除しました。大したことない。
テランス

2
私の答えをご覧ください。しかし、もっと真剣に、tee消費者については全く知りません。消費者は誰がbashラインを処理するかによって作られます。それbashは、開いているファイル記述子をコピーするだけです。さらに、複数のコンシューマーが同じファイルで開かれたファイル記述子に書き込みをします。カーネルがそれを処理しますが、確かにbashコマンドラインに表示される順序は重要ではありません。
マテイデビッド

17

teeストリームを部分に分割する必要があります。試してください:

cat testfile | tee >(wc -l) >(wc -w) >(wc -c) | tail -n 5

ノート:

  • 複数のプロセス(wctail)がすべてstdoutに書き込んでいる場合:

    • 出力が文字化けする場合があります。

    • 出力が表示される順序についての保証はありません。これを確認するにはsleep 1; wc -w、2番目のコンシューマーとして試してください。

  • tee宛先のいずれかがストリームを十分に速く消費しない場合、ブロックします。つまり、宛先にはほぼ同じ速度で入力が送られます(固定サイズのバッファリングをモジュロ)。これを簡単に修正する方法はありません。唯一の代替方法は、ストリームをファイルに保存し、それを個別にコンシューマにフィードすることです。以下のためにwctail、これは問題ではありません。

最後の言葉は、もっと簡単です。

echo "some random words" | awk '{print $NF}'

5

このmoreutilsパッケージには、peeまさにそれを行うコマンド(パイプとティーのマージ、どう思いましたか?)が含まれています。

最初の例では、次を使用します。

cat testfile | pee wc "tail -n 5"

2番目の例は、最後のコマンドに2つの入力を渡すため、より複雑です。私はおそらくawk他の答えとして使用します。

リンク:https : //joeyh.name/code/moreutils/

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.