Я пытаюсь остановить 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"