0

I am trying to stop tomcat on a remote server using a bash script. Here is the function:

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
}

Then inside a case statement this function is called.

My problem is if I just copy the output the echo $COMMAND statement and run it as independent command it works perfectly. But when it is run in the script it gives an error:

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

Can somebody please explain how this can be achieved inside a bash script?

Pritam Barhate
  • 129
  • 1
  • 8

1 Answers1

0

Short answer: see BashFAQ #50: I'm trying to put a command in a variable, but the complex cases always fail!.

Long answer: Putting commands in variables doesn't work right because of the order the shell parses things. Specifically, it parses quotes, escapes, and such before it expands variables, so embedding quotes in variables doesn't work -- by the time they're in the command line, it's too late for them to do anything useful.

It'd be possible to store the command in an array instead of a plain variable, and then use printf %q to quote any parts that need it for printing:

[...]
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[@]}"

The problem with this is that it there are many ways to quote/escape a variable with spaces, and %q may not pick one you like. Another option is to skip storing the command, and just print it "by hand":

[...]
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"
Gordon Davisson
  • 11,036
  • 3
  • 27
  • 33