Ssh

使用“curl | bash”回饋遠端執行腳本

  • August 18, 2013

我正在使用大量此類命令的平台上工作: ssh login@server.com 'curl http://some_server/script.sh | bash'

這對於遠端執行腳本非常乾淨和方便,但是,我無論如何都看不到獲取腳本的輸出/退出程式碼。任何人都可以找出一些東西來確保腳本已正確執行(從主機啟動 ssh 的角度來看)。

正如@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啟用了該選項(請參閱The Set Builtin)。如果pipefail啟用,則管道的返回狀態是最後一個(最右邊)以非零狀態退出的命令的值,或者如果所有命令都成功退出,則為零。

旁注:bash文件之所以相關,不是因為您通過管道傳輸到bash,而是因為(我假設)它是您的遠端使用者的登錄 shell,因此將是解釋遠端命令行並處理管道執行的程序。如果使用者有不同的登錄 shell,請參閱該 shell 的文件。

作為一個具體的例子,

( echo whoami ; false ) | bash
echo $?

產生輸出

login
0

證明bash管道末尾的 將掩蓋由 . 返回的錯誤狀態false。只要成功執行,它就會返回 0 whoami

相比之下,

set -o pipefail
( echo whoami ; false ) | bash
echo $?

產量

login
1

從而上報流水線前半部分的故障。


那麼,將它們放在一起,解決方案應該是

ssh login@server.com 'set -s pipefail ; curl -fsS http://some_server/script.sh | bash'

這樣,如果以下任何一項返回非零,您將獲得非零退出狀態:

  • ssh
  • 遠端登錄shell
  • curl
  • 在管道的bash末端

此外,如果curl -fsS檢測到異常的 HTTP 狀態碼,則會:

  • 抑制它的 STDOUT,這樣就不會通過管道傳輸任何內容bash來執行
  • 返回一個非零值,該值一直正確傳播
  • 向其 STDERR 列印一條診斷消息,該消息也一路傳播

引用自:https://serverfault.com/questions/505430