为什么这款 T 恤会丢失标准输出?

6 linux ssh bash pipe tee

简单的脚本:

#!/bin/bash
remote_ssh_account="depesz@localhost"
directory_to_tar=pgdata
exec nice tar cf - "$directory_to_tar" | \
    tee >(
        md5sum - | \
        ssh "$remote_ssh_account" 'cat - > /tmp/h3po4-MD5-2012-03-13.tar'
    ) | \
    ssh "$remote_ssh_account" 'cat - > /tmp/h3po4-data-2012-03-13.tar'
Run Code Online (Sandbox Code Playgroud)

理论上它应该将数据和校验和传送到远程机器。

但不知何故,T恤失败了:

tee: standard output: Resource temporarily unavailable
Run Code Online (Sandbox Code Playgroud)

做了strace,但没有任何结果。我看到两个 ssh 都启动了,并且 tee 向它们写入,但只有 ( md5sum | ssh ) 的管道获取数据 - ssh“数据”的 strace 没有获取任何数据,5 秒后 tee 显示错误。

除此之外所有的工作。建立了 2 个连接,tar 工作,md5sum 及其交付工作。

BMD*_*Dan 5

发现问题。这是 的相关部分strace

[pid 10243] write(1, "pFl\r\347\345]\244Hi\336\253,-\231\247\344\234\241\332\302\252\315\243G\234\225+\241\323\316s"..., 4096 <unfinished ...>
[pid 10247] select(7, [3 4], [3], NULL, {10, 0} <unfinished ...>
[pid 10243] <... write resumed> )       = -1 EAGAIN (Resource temporarily unavailable)
[pid 10247] <... select resumed> )      = 1 (out [3], left {10, 0})
[pid 10243] write(2, "tee: ", 5tee:  <unfinished ...>
(...)
[pid 10243] write(2, "standard output", 15standard output <unfinished ...>
(...)
[pid 10243] write(2, ": Resource temporarily unavailab"..., 34: Resource temporarily unavailable) = 34
Run Code Online (Sandbox Code Playgroud)

因此,发生的情况是远程 ssh 尚未准备好继续写入。大多数程序都能正确处理这个问题,但 tee 决定死在一堆。有关此类行为的参考,请参见http://lists.freebsd.org/pipermail/freebsd-bugs/2012-February/047528.html。在简短搜索“EAGAIN tee”时,我也发现了其他几个。

lhunath 找到的解决方案有效,因为它有效地强制 bash 处理EAGAIN. 优雅的。


小智 4

试试这个,这是解决管道破裂的另一种方法:

#!/bin/bash
remote_ssh_account="depesz@localhost"
directory_to_tar=pgdata
nice tar cf - "$directory_to_tar" | \
    tee >(
        md5sum | \
        ssh "$remote_ssh_account" 'cat > /tmp/h3po4-MD5-2012-03-13.sum'
    ) > >(
        ssh "$remote_ssh_account" 'cat > /tmp/h3po4-data-2012-03-13.tar'
    )
Run Code Online (Sandbox Code Playgroud)