Linuxで2つの名前付きパイプを単一の入力ストリームに結合するにはどうすればよいですか


64

|Linux のパイプ()機能を使用すると、標準入力を1つまたは複数の出力ストリームにフォワードチェーンできます。

tee出力を別々のサブプロセスに分割するために使用できます。

2つの入力ストリームを結合するコマンドはありますか?

これについてどうすればいいですか?diffはどのように機能しますか?

回答:


105

個人的に、私のお気に入り(ほとんどのLinuxディストリビューションで標準であるbashおよびその他のものが必要です)

詳細は、2つのものの出力内容とそれらのマージ方法に大きく依存します...

出力内のコマンド1とコマンド2の内容:

cat <(command1) <(command2) > outputfile

または、両方のコマンドが同じデータの別のバージョンを並べて表示する場合(snmpwalkでこれを使用しました。一方の番号と他方のMIB名)。

paste <(command1) <(command2) > outputfile

または、2つの同様のコマンドの出力を比較する場合(2つの異なるディレクトリでの検索など)

diff <(command1) <(command2) > outputfile

または、それらが何らかの順序で出力されている場合、それらをマージします。

sort -m <(command1) <(command2) > outputfile

または、両方のコマンドを一度に実行します(ただし、少しスクランブルをかけることができます)。

cat <(command1 & command2) > outputfile

<()演算子は、各コマンドの名前付きパイプ(または/ dev / fd)をセットアップし、そのコマンドの出力を名前付きパイプ(または/ dev / fdファイルハンドルリファレンス)にパイプで渡し、その名前をコマンドラインに渡します。>()と同等のものがあります。command0 | tee >(command1) >(command2) >(command3) | command4たとえば、1つのコマンドの出力を4つの他のコマンドに同時に送信することができます。


驚くばかり!私はbashのマンページを何度も読みましたが、それを選択していませんでした
ハビエル

2
参照は[詳細なbashスクリプトガイド](tldp.org/LDP/abs/html/process-sub.html)のLinuxドキュメントプロジェクトで見つけることができます
ブライス

3
パイプを介してインターリーブされた行を防ぐことができましたgrep --line-buffered- 複数のログファイルを同時にgrep'処理するのに便利tailです。参照stackoverflow.com/questions/10443704/line-buffered-cat
RubyTuesdayDONO

16

catゴリラが示すように、2つのスチームを別のスチームに追加できます。

また、FIFOを作成し、コマンドの出力をそれに向けて、他のプログラムでFIFOから読み取ることもできます。

mkfifo ~/my_fifo
command1 > ~/my_fifo &
command2 > ~/my_fifo &
command3 < ~/my_fifo

ファイルの書き込みまたは読み取りのみを行うプログラム、またはstdout / fileのみを出力するプログラムと他のファイルのみをサポートするプログラムの混合に特に役立ちます。


2
これはpfSense(FreeBSD)で動作しますが、受け入れられた答えは動作しません。ありがとうございました!
ネイサン

9
(tail -f /tmp/p1 & tail -f /tmp/p2 ) | cat > /tmp/output

/tmp/p1そして、/tmp/p2しながら、あなたの入力パイプされる/tmp/output出力です。


6
注:側の両方のコマンドがない限り()、すべての行(およびアトミックための他のいくつかのあいまいなPOSIX規則)上のフラッシュ、その出力は、あなたはいくつかの奇妙なが...猫への入力にスクランブルで終わる可能性
freiheit

アンパサンド文字の代わりにセミコロンを使用しないでください?
サミール

これはエピックものです
Mobigital

5

このための特別なプログラムを作成しました:fdlinecombine

複数のパイプ(通常はプログラム出力)を読み取り、それらを行単位でstdoutに書き込みます(セパレーターをオーバーライドすることもできます)


広告どおりに機能します。公開していただきありがとうございます。
アレクセイ

3

私がこれに使用した本当にクールなコマンドはtpipe、それほど一般的ではないので、コンパイルする必要があるかもしれません。あなたが話していることを正確に行うのに本当に素晴らしいし、とてもきれいなので、通常はインストールします。manページはhttp://linux.die.net/man/1/tpipeにあります。現在リストされているダウンロードは、このアーカイブhttp://www.eurogaran.com/downloads/tpipe/にあります

このように使用されます

## Reinject sub-pipeline stdout into standard output:
$ pipeline1 | tpipe "pipeline2" | pipeline3

3

ここで注意してください。それらを単にcatするだけでは、望まない方法で結果が混在することになります。たとえば、ログファイルの場合は、一方の行をもう一方の行の途中に挿入したくないでしょう。それでいいなら

tail -f / tmp / p1 / tmp / p2> / tmp / output

動作します。それがうまくいかない場合、行バッファリングを行い、完全な行のみを出力するものを見つける必要があります。Syslogがこれを行いますが、他に何ができるのかわかりません。

編集:バッファーなしの読み取りと名前付きパイプの最適化:

/ tmp / p1、/ tmp / p2、/ tmp / p3を「mkfifo / tmp / p N」によって作成された名前付きパイプと見なす

tail -q -f / tmp / p1 / tmp / p2 | awk '{print $ 0> "/ tmp / p3"; close( "/ tmp / p3"); fflush();} '&

これで、次の方法でバッファされていないパイプ "/ tmp / p3"という名前の出力を読み取ることができます。

tail -f / tmp / p3

ちょっとしたバグがあります。最初の入力パイプ/ tmp / p1を「初期化」する必要があります。

echo -n> / tmp / p1

以下のために最初の第二のパイプを/ tmp / P2からの入力を受け入れ、何かが/ tmpに/ P1に来るまで待つことはありません。これは当てはまらない可能性があります。確かな場合は、/ tmp / p1が最初に入力を受け取ります。

また、-qオプションをするために必要とされるテールのファイル名についてのゴミを印刷しません。


より便利になります:「テール-q -f / tmpに/ P1を/ tmp / P2 | another_command」それは行ずつ行われると-qオプションを指定して、それが他のゴミを印刷しないよう
readyblue

バッファリングされていないファイル/名前付きパイプの使用: tail -q -f /tmp/p1 /tmp/p2 | awk '{print $0 > "/tmp/p3"; close("/tmp/p3"); fflush();}' & / tmp / p3を名前付きパイプにすることもできます。tail -f /tmp/p3これは、UNBUFFERED =行ごとに読み取ることができます が、小さなバグがあります。テールが2番目からの出力を受け入れるために、最初のファイル/名前付きパイプを最初に初期化する必要があります。そのためecho -n > /tmp/p1、すべてがスムーズに機能する必要があります。
readyblue 14年

1

これを行うための最適なプログラムはlmergeです。freihartの答えとは異なり、2つのコマンドの出力が互いに混同しないように、ライン指向です。他のソリューションとは異なり、入力をかなりマージするため、出力を支配するコマンドはありません。例えば:

$ lmerge <(yes foo) <(yes bar) | head -n 4

以下を出力します。

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