使用“curl | bash”反馈远程执行脚本

rmo*_*njo 5 remote-access ssh bash remote curl

我正在一个使用很多这样的命令的平台上工作: ssh login@server.com 'curl http://some_server/script.sh | bash'

这对于远程执行脚本来说非常干净和方便,但是,无论如何我都看不到获取脚本的输出/退出代码。任何人都可以找出一些方法来确保脚本已正确执行(从启动 ssh 的主机的角度来看)。

200*_*ess 7

正如@Zoredache 指出的那样,ssh将远程命令的状态作为其自己的退出状态进行中继,因此错误检测可以通过 SSH 透明地工作。但是,在您的示例中,有两点需要特别考虑。

首先,curl往往非常宽容,将许多异常情况视为成功。例如,curl http://serverfault.com/some-non-existent-url-that-returns-404实际上退出状态为 0。我发现这种行为违反直觉。要将这些条件视为错误,我喜欢使用以下-fsS标志:

  • --fail标志会在发生故障时抑制输出,因此bash不会有机会像执行代码一样执行 Web 服务器的 404 错误页面。
  • 这些--silent --show-error标志一起提供了合理数量的错误报告。 --silent禁止来自 的所有评论curl--show-error重新启用发送到 STDERR 的错误消息。

其次,您有一个管道,这意味着第一个或第二个命令可能会发生故障。从关于bash(1) 中的管道部分:

管道的返回状态是最后一个命令的退出状态,除非pipefail启用了该选项(请参阅Set Builtin)。如果pipefail启用,则管道的返回状态是以非零状态退出的最后一个(最右侧)命令的值,如果所有命令都成功退出,则为零。

旁注:bash文档是相关的,不是因为您通过管道连接到bash,而是因为(我假设)它是您的远程用户的登录 shell,因此将是解释远程命令行并处理管道执行的程序。如果用户有不同的登录 shell,请参阅该 shell 的文档。

作为一个具体的例子,

( echo whoami ; false ) | bash
echo $?
Run Code Online (Sandbox Code Playgroud)

产生输出

login
0
Run Code Online (Sandbox Code Playgroud)

证明bash管道末尾的 将屏蔽由 返回的错误状态false。只要成功执行它就会返回 0 whoami

相比之下,

set -o pipefail
( echo whoami ; false ) | bash
echo $?
Run Code Online (Sandbox Code Playgroud)

产量

login
1
Run Code Online (Sandbox Code Playgroud)

以便报告管道前半部分的故障。


把它们放在一起,那么,解决方案应该是

ssh login@server.com 'set -s pipefail ; curl -fsS http://some_server/script.sh | bash'
Run Code Online (Sandbox Code Playgroud)

这样,如果以下任何一项返回非零,您将获得非零退出状态:

  • ssh
  • 远程登录shell
  • curl
  • bash在管道末端

此外,如果curl -fsS检测到异常的 HTTP 状态码,那么它将:

  • 抑制它的 STDOUT,这样就不会通过管道bash执行任何操作
  • 返回一个一直正确传播的非零值
  • 向其 STDERR 打印一行诊断消息,该消息也一直传播