Ssh

遠端 SSH 命令有效,但在 bash 腳本中使用時無效

  • March 2, 2016

我正在嘗試使用 bash 腳本在遠端伺服器上停止 tomcat。這是功能:

function stop_remote_tomcat () {
   CURRENT_SERVER=$1
   CURRENT_USER=$2
   CURRENT_PEM_FILE=$3

   COMMAND="ssh -i $CURRENT_PEM_FILE $CURRENT_USER@$CURRENT_SERVER \"/bin/sh sudo /etc/init.d/tomcat stop\""
   echo $COMMAND
   $COMMAND
}

然後在 case 語句中呼叫這個函式。

我的問題是,如果我只是複制echo $COMMAND語句的輸出並將其作為獨立命令執行,它就可以完美執行。但是當它在腳本中執行時會出現錯誤:

sudo /etc/init.d/tomcat stop: No such file or directory

有人可以解釋一下如何在 bash 腳本中實現這一點嗎?

簡短回答:參見BashFAQ #50:我試圖將命令放入變數中,但複雜的情況總是失敗!.

長答案:由於shell解析事物的順序,將命令放入變數中不起作用。具體來說,它會在擴展變數之前解析引號、轉義符等,因此在變數中嵌入引號是行不通的——當它們在命令行中時,它們做任何有用的事情都為時已晚。

可以將命令儲存在數組而不是普通變數中,然後用於printf %q引用需要列印的任何部分:

[...]
COMMAND=(ssh -i $CURRENT_PEM_FILE $CURRENT_USER@$CURRENT_SERVER "/bin/sh sudo /etc/init.d/tomcat stop")
printf "%q " "${COMMAND[@]}"
echo    # Because printf won't add a linefeed
"${COMMAND[@]}"

這樣做的問題是,有很多方法可以用空格引用/轉義變數,並且%q可能不會選擇你喜歡的一個。另一種選擇是跳過儲存命令,直接“手動”列印:

[...]
echo "ssh -i $CURRENT_PEM_FILE $CURRENT_USER@$CURRENT_SERVER \"/bin/sh sudo /etc/init.d/tomcat stop\""
ssh -i $CURRENT_PEM_FILE $CURRENT_USER@$CURRENT_SERVER "/bin/sh sudo /etc/init.d/tomcat stop"

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