让我们分析你的命令:
回声
echo部分,简单的输出foobar。
只是碰巧 foo 的退出时间与 bar 不同:
$ (echo -n foo; sleep 1; echo bar)
foobar
$ (echo -n foo; sleep 1; echo bar) | cat
foobar
阅读
读取部分只是在变量中获取该输出:
$ (echo -n foo; sleep 1; echo bar) | { read -t2 r; echo "###$r@@@"; }
###foobar@@@
如果睡眠时间大于读取超时时间,则读取一无所获:
$ (echo -n foo; sleep 4; echo bar) | { read -t2 r; echo "###$r@@@"; }
###@@@
虽然(多行)。
一段时间后,重复读取。一些读取获得所有输入,然后,在管道关闭后,读取立即获得 EOF(发生这种情况时它不会等待超时)。发生这种情况时它会返回一个错误,但没有检查 read 是否有错误,因此循环重复。
所以:创建了许多行:
$ (echo -n foo; sleep 1; echo bar) |
{ while :; do read -t2 r; echo "###$r@@@"; done; }
我们可以将输出重定向到一个文件(testfile.txt),而且,我们可以控制它的工作时间(为了便于阅读,分成三行)(> 不是命令的一部分):
$ { echo -n foo; sleep 1; echo bar; } | {
> while :; do read -t2 r; echo "###$r@@@"; \
> done; } > testfile.txt & sleep 2; kill $!
[1] 28541
[1]+ Terminated ....
现在我们可以看到写了多少行:
$ wc -l testfile.txt
35543 testfile.txt
这意味着每秒大约有 35k 行写入文件。
最后一次睡眠后(杀死前)的数字必须大于第一次睡眠时的数字,否则不会将任何行写入文件。
哪几行:
其中哪些不是重复###@@@:
$ grep -vn "^###@@@"
1:###foobar@@@
所以,只有文件的第一行实际包含信息,其余的是###@@@的连续重复。
睡眠少于阅读-t
如果睡眠时间 (1) 低于读取超时 (2),就会发生这种情况。 1 表示睡眠,2 表示阅读。
睡眠时间比阅读时间长-t
如果我们让休眠时间长于读取超时时间:
$ a=3; b=2; c=5
$ { echo -n foo; sleep $a; echo bar; } | {
> while :; do read -t$b r; echo "###$r@@@"; \
> done; } > testfile.txt & sleep $c; kill $!
[1] 29032
[1]+ Terminated ........
$ wc -l testfile.txt
65226 testfile.txt ### Again ~ 30 k per second.
$ grep -vn "^###@@@" testfile.txt
2:###bar@@@
结论?
似乎正在发生的事情是,在回显写入其输出之后,while 会不断重复读取接收“空”输入,并将其写入文件(尽可能多的 ###@@@ 行)。
只有当第一个回显睡眠时间长于第一个读取超时 (b=2) 时 (a=3),我们才会在 foo 和 bar 两个不同的行中得到一个划分。
这似乎是说foo 在时间 0 熄灭,第一次读取超时而没有收到完整的行,并发出初始 ###@@@(吃掉 foo 而没有输出?)。然后bar 带有第二次读取的结束换行符,此读取发出###bar@@@。由于管道的左侧已终止,因此 read 不断产生空行。
如果睡眠时间为 4,超时时间为 2,(根据您的问题)超时可能会发生两次,并且可能会在输出中写入两行。这将使bar 成为第三行(两次超时,在小节线旁边),但这并不能保证,因为两个睡眠控制着这一点,它们可能会徘徊一点。
在管道左侧的所有输出都已发出之后。读取接收到许多“空行”???。哪些被写入文件,我们可以分析它们。
一些松散的问题。
静态(暂时)读取。
我们可以做一个更具体的命令来分析:
$ { echo 'foo'; sleep 3; echo 'bar'; } |
{ read -t1 r; echo "read r value=|$r|"; \
read -t1 s; echo "read s value=|$s|"; }
read r value=|foo|
read s value=||
如果睡眠 (3) 比读取时间长,则仅读取第一个 foo。
$ { echo 'foo'; sleep 1; echo 'bar'; } |
{ read -t2 r; echo "read r value=|$r|"; \
read -t2 s; echo "read s value=|$s|"; }
read r value=|foo|
read s value=|bar|
如果输入出现的读取超时时间较长,foo 和 bar 都会被读取。
虽然
如果我们包含一个简单的 while:
{ echo -n foo; sleep 4; echo bar; } | {
while read -t2 r; do
echo "###$r@@@";
done;
}
仅当睡眠低于读取超时时,我们才不会得到输出:完整的 foobar。
如果睡眠时间长于读取超时:第一次读取失败,退出代码为 1,并且退出 while。
这就是为什么我们会获得无限的时间。但这需要一个文件和一个最终超时,在代码中:
a=3; b=2; c=5
{ echo -n foo; sleep $a; echo bar; } | {
while :; do
read -t$b r;
echo "###$r@@@";
done;
} > testfile.txt & sleep $c; kill $!
wc -l testfile.txt; grep -vn "^###@@@" testfile.txt