IOストリームの一般的な分割+マージ構文を探す

IOストリームの一般的な分割+マージ構文を探す

必要な作業を頻繁に行いたい。

  1. stdoutパイプライン(パイプと呼ばれる)をpipeline-before2つの並列ストリームに分割します。
  2. 結果ストリーム(stdin)を2つの別々のパイプ(pipeline-between-0およびpipeline-between-1)に供給します。
  3. 2つの結果stdoutストリームのマージ厳格な順序で;
  4. マージされた結果ストリームをstdin別のパイプ(pipeline-after)に供給します。

(3)で「厳密な順序で」とは、すべての出力が出力の前にマージpipeline-between-0された出力ストリームに表示されることを意味しますpipeline-between-1

すべてをグラフィカルに表現できます。

pipeline-before --.--- pipeline-between-0 -.
                   \                        \
                    `- pipeline-between-1 ---`-- pipeline-after

pipeline-between-0これら/ペアの例はpipeline-between-1次のとおりです。

  1. head -n 1 | tr 'a-z' 'A-Z'
  2. tail -n +2 | sort -t $'\t' -k1,1

英語では、この組み合わせを「最初の行をすべて大文字にし、残りの行を最初の列に並べ替える」と説明します。

尋ねる:そのようなタスクを表現するための一般的なシェル構文はありますか?

私はこの質問に対する答えに興味がありますzshbash


一般的に言えば、これは構文です。いいえ働く:

$ pipeline-before | tee >( pipeline-between-0 ) | pipeline-between-1 | pipeline-after

この構文は、次の2つの理由で失敗します。

  1. の一部の出力がのpipeline-between-1一部の出力の前に表示されることがよくありますpipeline-between-0
  2. SIGPIPE結局、出力が切り捨てられます(信号によるものと思われます)。

私は次を試しました運動(私は100%理解していないことを認めます):

{
  pipeline-before |
  { tee >( pipeline-between-0 4>&1 1>&3 ); } |
  pipeline-between-1
} 3>&1 | pipeline-after

AFAICT、この構文は上記の最初の問題を解決するようです(つまり、いくつかの非公式テストに基づくpipeline-between-0出力はpipeline-between-1正しい順序で表示されます)。しかし、残念ながら、少なくともいくつかのケースでは、最終出力はまだ切り捨てられます。

ベストアンサー1

たぶん名前付きパイプ(FIFO)のみが必要な場合があります。

以下の例:

 { seq 1 100000 | grep 1$ & seq 1 100000 | grep 2$ ; } > unsorted

ファイル内の1と2で終わる数字の混合を返す必要がありますunsorted。私たちはそれらをソートしたいので(すべての数字は1で終わり、すべての数字は2で終わる)、各結果に1つずつ2つの名前付きパイプを作成し、必要な順序で組み合わせます。

mkfifo stream{1,2}
{ seq 1 100000 | grep 1$ >stream1 & seq 1 100000 | grep 2$ > stream2 ; } &\
cat stream1 stream2 > sorted

ファイルの順序が同じであることを確認してください。

diff -q {un,}sorted 

(それらは異なる必要があります)ソートされた順序が期待どおりであることを確認してください。

sed 1,10000q sorted | grep 2$

(結果があってはならず、unsortedファイルはデータを返す必要があります)

bash名前付きパイプは同じように機能する必要がありますzsh


または、擬似コードの最も一般的な表現は次のとおりです。

  1. tee入力ストリーム(「パイプ前」)は、FIFOを介して複数の並列ストリームにコピーされますin-i
  2. 各ストリームは異なる命令によって並列に処理され、対応する出力はストリームout-i(「i間のパイプ」)に送られる。
  3. 必要な順序で出力ストリームを接続し、次のコマンド(「アフターパイプ」)に渡します。

mkfifo {in,out}-{0..n}

pre-cmd | tee in-0 in-1 ... in-n | cat >/dev/null &
cmd-0 <in-0 >out-0 &
cmd-1 <in-0 >out-0 &
....
cmd-i <in-n >out-n &
cat out-0 out-1 ... out-n | after-cmd

私は一般化の理由でcat >/dev/null代わりに使用しています。同じ内容は(おそらく)最終的に重複します。cat >in-ncat

例:

mkfifo {in,out}-{0..2}
seq 0 100 | tee in-{0..2} | cat >/dev/null &
grep '33$' <in-0 >out-0 &
awk '$1<2' <in-1 >out-1 &
sed '/^.\{1,2\}$/d' <in-2 >out-2 &
cat out-2 out-0 out-1 | tr '\n' '-'

結果:100-33-0-1-

おすすめ記事