tee>(cat -n)< tmpfile在重复之前完全打印tmpfile

时间:2014-11-13 00:54:48

标签: bash process-substitution

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

由于tee和cat通过命名管道连接,我希望cat在T恤打印下一行之前完成向终端发送输出。像这样:

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

有人可以解释一下这里发生了什么吗?我考虑了竞争条件的可能性,即发球台刚刚获胜,但这种情况发生在大小等于几KB的文件中。我觉得这里有更多的东西。

感谢。

1 个答案:

答案 0 :(得分: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实现)写入每个块 - 每行; tee的POSIX规范明确禁止面向行的输出缓冲 - 首先是它的标准输出,然后是从左到右的每个参数。

您可以看到in the implementation

/* 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:1映射,并依次写入每个数组:

files

解释为什么这将以一种一致的行为而不是种族的方式实现 - the POSIX specification for tee要求它不缓冲输入。因此,在对每个描述符的写入之间必须保持排序(当然,如果在任何管道中的项目稍后自己进行缓冲,那么在该点之后排序可能会丢失)。


现在:表示/* 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在每个tee个字节的块中工作,其中BUFSIZ是特定于操作系统的常量,保证不小于256字节,并且在现代(非嵌入式)Linux中经常使用邻居8K。因此,如果您使用明显更大的输入,您将看到交错,正如您所期望的那样......但是按照一致的顺序,出于上面给出的原因。