使用“curl | bash”回饋遠端執行腳本
我正在使用大量此類命令的平台上工作:
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
。只要成功執行,它就會返回 0whoami
。相比之下,
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 列印一條診斷消息,該消息也一路傳播