プロセス置換を伴う出力指図


11

これは私が普通に実行するために行うものですgrepし、wcそれを2回スキャンすることなく、ファイルに

<file.txt  tee >(grep LITERAL) >(wc -l) >/dev/null

しかし、これは

EXEC LITERAL
32

時々そして

32
EXEC LITERAL

またある時には。(からgrepの出力wcは、最初のインスタンスからの出力に先行し、2番目のインスタンスではその逆です。)

一方、リダイレクトとファイル記述子では

{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1 

私はいつも得るようです

EXEC LITERAL
32

出力順序が予測可能であることを好みますが、2番目のアプローチで保証されますか?

回答:


4

両者に

<file.txt  tee >(grep LITERAL) >(wc -l) >/dev/null

そして:

{ { <file.txt tee /dev/fd/3 | grep LITERAL >&4; } 3>&1 | wc -l ;} 4>&1

すべてのteegrepそしてwc同時に開始されています。次に重要なのは、最後に何が起こるかです。

wc標準入力でファイルの終わりを検出した場合にのみ結果を出力します。最初のケースでteeは、それteeが終了するときfdです。これwcは、(プロセス置換によって開始された)読み取り元のパイプの反対側で終了するためです。grepその時間までにすべての入力を読み取り、その出力を書き込んだことは保証されません(パイプがかなりの量のデータを保持でき、それwcよりも高速である可能性が高いgrep

2番目のケースwcでは、読み取り元のパイプへのすべてのライターがパイプの終わりを閉じたときに、ファイルの終わりが表示されます。その場合でも、何人かの作家がいます。tee(上のFDオープン経由/dev/fd/3とし、そのFD 3を介して)grepも、その持っているfdのパイプにオープン3をwc(それはそれのいずれかを利用することしていないが、それにのみ書き込みをしましょう)。インナーは{おそらくもあります余分なサブシェルプロセスが発生しますfd3オープンにし、両方のを待ちますteeとをgrep

つまりwcgrepが終了した後にのみ行番号が書き込まれます。

あなたがそれを適切な方法で書いたなら、それはopenする必要のないfdsを閉じることによってです:

{ { <file.txt tee /dev/fd/3 4>&- | 
   grep LITERAL >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1

その場合、サブシェルプロセスを最適化するシェルでは、順序は保証されません。ただし、私が知っている唯一のシェルはパイプにソケットペアを使用しているksh93だけなksh93ので/dev/fd/3、少なくともLinuxでは動作しません。

プロセスが実行されているかを確認するには、置き換えることができgrepps

$ { { <file.txt tee /dev/fd/3 4>&- | ps -H >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1
  PID TTY          TIME CMD
 8727 pts/5    00:00:00 bash
 8815 pts/5    00:00:00   bash
 8817 pts/5    00:00:00     tee
 8818 pts/5    00:00:00     ps
 8816 pts/5    00:00:00   wc

を使用するとbash、追加のシェルプロセスを確認でき、次のコマンドを使用してfd 3でパイプが開かれていることも確認できます。

$ (p=$BASHPID; { { <file.txt tee /dev/fd/3 4>&- | lsof -ag "$p" -d3 >&4 3>&- 4>&-; } 3>&1 | wc -l 4>&-;} 4>&1)
COMMAND  PID PGID     USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
bash    9843 9842 chazelas    3w  FIFO    0,8      0t0 153304 pipe
tee     9845 9842 chazelas    3w  FIFO    0,8      0t0 153304 pipe
lsof    9846 9842 chazelas    3r   DIR    0,3        0      1 /proc

ありがとう。あなたの「適切な例」ではgrep LITERAL >&4 3>&- 4>&-、fd 4が使用され、閉じられているように見えますが、どういう意味ですか?
iruvar 2013

@ 1_CR、後>&4、の略で1>&4grepのfd 1と4は同じリソース(シェルの初期stdout)を指します。grepfd 4を何にでも開放する必要はありません。我々がそれを閉じるように、それはそれで何もしない4>&-
ステファンChazelas

最後のコマンドラインは不可解な魔法です。

-1

予測可能な注文を取得するには

(<file.txt  tee >(grep LITERAL) >(wc -l) >/dev/null)|sort

多分私は十分に明確ではなかった。コマンド出力の順序に関して予測可能な順序を意味しました(つまり、wcからの出力の前にgrepからの出力)。組み合わせた出力を並べ替える必要はありません
iruvar

gnu.org/software/bash/manual/bashref.html#Command-Groupingを見つけたところ、{}演算子を使用して(この場合は)最初に<file.txt tee / dev / fd / 3 | grep LITERAL>&4; これが完了したら、wcを呼び出すので、元の質問に答えるために、はい、それが私の理解に保証されます
Thorsten Staerk

1
@ThorstenStaerk見つけた追加情報を回答に追加できますか?
terdon

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