此代码以错误终止:
(
ssh localhost seq 100000
seq 100000
) | wc
#-> seq: write error: Resource temporarily unavailable
这是重现写入错误的最少代码。重点不是更改子进程/管道体系结构以使其工作,而是要理解为什么将 fd 1 分配给稍后重用以写入大输出的管道时会出现此错误。
为什么 SSH 客户端会留下 stdout 文件描述符脏?这是设计缺陷吗?是否可以选择让它像另一个进程那样工作?
编辑:感谢评论中的线索,我怀疑它可能与 OpenSSH 版本 7.9 到 8.4 有关
鉴于强烈的线索表明这是由于版本特定的回归,这里有三种方法来获取不依赖于 OpenSSH 版本的代码。
验证只有 fd 1 受到影响,fd 0 和 2 保持干净,fd 1 和 2 之间的排列是一种可能的解决方法。在下面的代码中,fd 2 变脏了,但除非在上面写入了足够数量的数据,否则不会出现缺陷,而 fd 1 是干净的:
或者使用额外的管道,将 ssh 包装在子进程中以隔离受影响的文件描述符:
如果您必须编写可能共享 stdout 文件描述符而不依赖于 OpenSSH 受影响版本的 SSH 调用,这可能是一个可以接受的缺点。
第三种方法是将受影响的 fd 分配给文件而不是直接分配给管道。这是执行此操作的功能:
编辑: https://bugzilla.mindrot.org/show_bug.cgi ?id=3280 已在 8.5 版中报告(但至少存在于 7.9 中)并在 8.9 版中关闭。如果你不能升级你的二进制文件,你可能想把这个带有基本名称的脚本
ssh
放在你的用户路径前面/usr/bin
: