Я пытаюсь остановить tomcat на удаленном сервере с помощью сценария bash. Вот функция:
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: Я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу!.
Длинный ответ: помещение команд в переменные работает неправильно из-за порядка, в котором оболочка анализирует вещи. В частности, он анализирует кавычки, экранирование и тому подобное, прежде чем расширять переменные, поэтому встраивание кавычек в переменные не работает - к тому времени, когда они находятся в командной строке, им уже слишком поздно делать что-нибудь полезное.
Можно было бы сохранить команду в массиве вместо простой переменной, а затем использовать 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"