1

tmpfile には次のものが含まれます。

a
b
c
d

質問のタイトルのコマンドの出力は次のとおりです。

[me@localhost somedir]$ tee >(cat -n) < tmpfile    
a
b
c
d
[me@localhost somedir]$      1  a
     2  b
     3  c
     4  d

ティーと猫は名前付きパイプを介して接続されているため、ティーが次の行を出力する前に、猫がターミナルへの出力の送信を完了することを期待していました。このようなもの:

[me@localhost somedir]$ tee >(cat -n) < tmpfile    
a
1  a
b
2  b
c
3  c
d
4  d
[me@localhost somedir]$     

誰かがここで何が起こっているのか説明してもらえますか? ティーがちょうど勝っている競合状態の可能性を考慮しましたが、これはサイズが数 KB のファイルでも発生します。ここにはもっと何かがあると感じています。

ありがとう。

4

1 に答える 1

2

これを反対側に勝ち取らせたい場合は、簡単に行うことができます (tee特定の順序付けは標準化されているのではなく、実装によって定義されているため、 の同じ実装を使用していると仮定します)。

# note that this uses automatic FD allocation support added in bash 4.1
( exec {orig_stdout}>&1; { tee >(cat >&$orig_stdout) | cat -n; } <<<$'a\nb\nc' )

要するに: tee(GNU coreutils 8.2.2 で実装されているように) 各行ではなく、各チャンクを書き込みます。の POSIX 仕様では、tee行指向の出力バッファリングが明示的に禁止されています。最初は標準出力へ、次に各引数へ、左から右へ。

実装でそれを見ることができます:

/* Move all the names 'up' one in the argv array to make room for
   the entry for standard output.  This writes into argv[argc].  */
for (i = nfiles; i >= 1; i--)
  files[i] = files[i - 1];

...次にdescriptors、 の配列エントリを使用して 1:1 でマッピングされた配列filesを作成し、それぞれに順番に書き込みます。

/* Write to all NFILES + 1 descriptors.
   Standard output is the first one.  */
for (i = 0; i <= nfiles; i++)
  if (descriptors[i]
      && fwrite (buffer, bytes_read, 1, descriptors[i]) != 1)

これが競合ではなく一貫した動作になるように実装される理由を説明すると、tee の POSIX 仕様では、入力をバッファリングしないことが要求されています。したがって、順序は各記述子への書き込み間で維持される必要があります (もちろん、後でパイプライン内の項目がそれ自体をバッファリングする場合、順序はその時点以降に失われる可能性があります)。


現在: これは、次の場所に進む前に完全な入力を各場所にコピーするということではありません。teeむしろ、tee はBUFSIZそれぞれバイトのブロックで動作します。ここで、BUFSIZは 256 バイト以上であることが保証されているオペレーティング システム固有の定数であり、最近の (組み込みではない) Linux では 8K 付近で頻繁に動作します。したがって、非常に大きな入力を使用すると、期待どおりにインターリーブが表示されますが、上記の理由により、一貫した順序で表示されます。

于 2014-11-13T01:08:18.680 に答える