web-dev-qa-db-ja.com

コマンドの出力を複数のコマンドにリダイレクトすることは可能ですか?

私の知る限り、teeコマンドを使用して、標準出力を画面とその他のファイルに分割できます。

command -option1 -option2 argument | tee file1 file2 file3 

Teeを使用してファイルではなくコマンドに出力をリダイレクトして、理論的にコマンドのチェーンを作成することは可能ですか?

21
Abdul Al Hazred

teeのコマンドラインで名前付きパイプ( http://linux.die.net/man/1/mkfifo )を使用して、名前付きパイプでコマンドを読み取ることができます。

mkfifo /tmp/data0 /tmp/data1 /tmp/data2
cmd0 < /tmp/data0 & cmd1 < /tmp/data1 & cmd2 < /tmp/data2 &
command -option1 -option2 argument | tee /tmp/data0 /tmp/data1 /tmp/data2

commandが完了すると、teeは名前付きパイプを閉じます。これにより、各/tmp/dataNでEOF(0バイトの読み取り))が通知されます通常はcmdNプロセスを終了します。実際の例:

$ mkfifo /tmp/data0 /tmp/data1 /tmp/data2
$ wc -l < /tmp/data0 & wc -w < /tmp/data1 & wc -c < /tmp/data2 &
$ tee /tmp/data0 /tmp/data1 /tmp/data2 < /etc/passwd >/dev/null
$ 61
1974
37

バックグラウンドプロセスのため、シェルはプログラム出力の前にプロンプ​​トを返しました。 wcの3つのインスタンスはすべて正常に終了しました。

24
Arcege

私が正しく理解していれば、tee file1 file2 file3に相当するものを探していますが、同じデータを3つのファイルfile1file2およびfile3に書き込むのではなく、同じデータを3つのコマンドcmd1cmd2およびcmd3にパイプします。つまり、.

… | ??? cmd1 cmd2 cmd3

同等である必要があります

… | cmd1 &
… | cmd2 &
… | cmd3 &

ただし、は1回だけ実行されます。

それには2つの方法があります。

Ksh93、bash、およびzshは プロセス置換 をサポートします。これは、コマンドの引数を、書き込み時にコマンドへの入力としてデータを渡すファイルにすることを可能にするパイプの一般化です(読み込まれると、コマンドによってデータ出力を取得する入力バリアントもあります)。 。あれは、

echo hello | tee >(cmd1)

helloを標準出力に出力し、さらにhelloを入力としてcmd1を実行します。

たとえば、somecommandの入力を複製してcmd1cmd2の両方に渡す場合は、次のように使用できます。

somecommand | tee >(cmd1) | cmd2

シェルがプロセス置換をサポートしていない場合は、代わりに名前付きパイプを使用できます。それがどのように機能するかについては Arcege's answer を参照してください。名前付きパイプは、作成して削除し、プロセスを手動で開始および同期する必要があるため、プロセス置換よりも便利ではありません。すべてのシェルがプロセスの置換をサポートしているわけではないのに、完全に移植可能であるという利点があります。これらは、プロセス置換が対象とするシナリオ以外のシナリオでも使用できます。

内部では、一部のシステムでは、プロセス置換は内部で名前付きパイプを使用します。ただし、ほとんどのシステムでは ファイル記述子を表す名前付きファイル に依存しています。

少なくとも bash では、プロセス置換を使用してmkfifoをスキップできます。

command -option1 -option2 argument | tee >(cmd1) >(cmd2) >(cmd3)

または採用するには アルセジュの例

tee >(wc -l) >(wc -w) >(wc -c) < /etc/passwd >/dev/null
6
Tobias Kienzler

Moreutils( https://joeyh.name/code/moreutils )のpeeコマンドについてだれも言及していないことに驚いています。

3
Lexelby