通过ssh执行管道命令的退出状态

3
我正在通过ssh在bash中执行一个管道命令链。如果任何一个命令失败,我想要退出。如果整个管道执行完成后发生退出也可以。如果其中一个命令失败,我只想给管道指定一个总的'fail'状态。
一个简单的例子是: ssh $REMOTE_HOST "CMD1 | CMD2" >> file.txt 如果我在本地执行命令链,我可以使用${PIPESTATUS[0]}来获取链中任何命令的退出状态。但是通过ssh,我得到的是最后一个命令的退出状态。例如,如果CMD1失败而CMD2成功,则localhost上的$?将给我返回0。如果CMD1失败,如何将一个总的失败状态分配给整个管道呢?

关于编程的内容翻译:与“over ssh”无关是问题的重点--您可以去掉SSH,仍然面临同样的问题。在下次提问之前,请考虑将其作为找到问题核心的一部分。 - Charles Duffy
正如我的问题所述,我能够运行PIPESTATUS来提取在本地运行时链中任何命令的退出状态。据我回忆,我无法使用PIPESTATUSssh上运行并获取“总体”退出状态。因此需要这个额外的说明。 - RDK
PIPESTATUS 不会传输到本地 shell,但是你可以在远程端运行它。也就是说:ssh "$host" bash <<<'CMD | CMD2; exit $((PIPESTATUS[0] | ${PIPESTATUS[1]}))' - Charles Duffy
@CharlesDuffy 我明白。但这会让我的命令变得复杂。例如,我可能需要使用类似于 STATUS=$(ssh "cmd1 | cmd2; PIPESTATUS[*]") 的东西,然后跟着 if [ STATUS -ne 0 ] ... - RDK
我现在明白为什么指定SSH是有意义的。 - Charles Duffy
1个回答

5

由于这个问题标记了 bash,我假设您的远程用户的默认 shell 是 Bash。在这种情况下,您应该通过 set -o pipefail 设置 pipefail 选项。根据上面链接的Bash参考手册:

如果设置了,一个管道的返回值是最后一个(最右边的)以非零状态退出的命令的值,如果管道中的所有命令都成功退出,则返回0。此选项默认情况下被禁用。

例如,请尝试:

ssh $REMOTE_HOST 'false | true'
ssh $REMOTE_HOST 'set -o pipefail; false | true'

查看ssh命令的退出状态差异。


另一方面,如果远程用户的默认shell是zsh,那么您应该使用setopt pipe_fail。请注意,这是zsh的相对较新的添加功能。我不能确定它是何时添加的,但我知道它适用于5.0.5但不适用于5.0.2。


我想我之前误读了问题的第一行,认为你是在bash中执行ssh命令,但我无法推断出你的远程shell。很抱歉。无论如何,我相信提供关于zsh的附加信息没有任何问题。 - 4ae1e1
我的本地和远程shell都是bash。set -o pipefail正好符合我的意图。 - RDK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接