关于 ls、dir 和 tee 的混淆

A confusion about ls, dir and tee

我知道 tee 将从 STDIN 读取并创建一个新文件。但是当它带有 ls 时,哪个过程先发生?

例如:

➤ ls
12  123  1234
➤ ls | tee hello
12
123
1234
hello # ls catch hello
➤ ls | tee 000
12
123
1234
hello # ls didn't get 000
➤ ls | tee 0
000
12
123
1234
hello # ls didn't get 0
➤ ls | tee 00000
0
000
00000 # ls did get 00000
12
123
1234
hello
➤ 

但是说到 dir:

➤ ls
12  123  1234
➤ dir | tee hello
12  123  1234  hello # get hello
➤ dir | tee 000
000  12  123  1234  hello
➤ dir | tee 0
0  000  12  123  1234  hello #get 0
➤ dir | tee 000000
0  000  12  123  1234  hello # didn't get 00000
➤ dir | tee 01
0  000  000000  01  12  123  1234  hello
➤ dir | tee 000000000000000000000000
0  000  000000  000000000000000000000000  01  12  123  1234  hello #get 00000000..000
➤ 

为什么?哪个先发生? tee 创建新文件或 ls/dir 输出?

两个程序同时运行。当管道左侧的进程正在将输出写入管道时,管道右侧的进程正在从中读取。

tee 将在开始后立即创建输出文件,然后再从输入中读取。这就是为什么有时(!)可以在 ls 的输出中看到文件 dir 的输出。但是,不能保证。一般取决于每个进程什么时候进入the/aCPU以及循环多少次,打开文件需要等待多长时间tee等等。

实际上在我的测试系统上,文件几乎总是显示为 lsdir。但有时列表中的文件又丢失了 lsdir.

这实际上是一个process-race-condition在一个directory-resource上的情况,因为两个进程都执行并行

Each command in a pipeline is executed as a separate process (i.e., in a sub-shell).

管道的想法是将与可执行文件 exec_A 关联的进程 A 中的 output 重定向到与可执行文件 exec_B 关联的进程 B :

exec_A | exec_B

如何做到这一点在很大程度上取决于实现,但考虑到实际限制,操作系统必须创建一个缓冲区来放置 A 的输出并强制 B 从该缓冲区读取。这发生在进程开始之前。

所以发生的事情是这样的:

exec_A &> buf ; exec_B < buf &

进程在内部如何处理它们接收或写入的数据取决于进程的实现。在这种情况下,tee 正在创建将在进程启动时写入的文件,这绝对合乎逻辑,因为它需要附加传入数据。

鉴于此,这取决于进程 A(即 ls/dir)是否在进程 B 打开文件之前完成其目录遍历。这实际上取决于谁获得了资源父级的锁。

您实际上可以观察到 ls 几乎总是输出这样创建的资源:

ls * | tee subdir/0

因为它在 subdir 上获得了锁。