How to force ssh to execute command on the remote system instead of locally

I have SSH executing some commands in a script, like so:

#!/bin/bash

REMOTEUSER=$1
REMOTEHOST=$2    
newVh=$3

ssh "$REMOTEUSER"@"$REMOTEHOST" << EOF

cd

if [ ! -d "/data/web/someDirectory" ]
then
  echo -e "There is no vhost setup for someDirectory"
  exit 1
fi


if [ ! -d "git" ]
then
  echo -e "Home git directory not found. Creating it now."
  mkdir git
fi

if [ ! -d "git/$newVh.git" ]
then
  echo -e "Bare git repository not found for $new. Creating it now."
  mkdir git/"$newVh".git
  git init --bare git/"$newVh".git
fi


EOF

Which works fine and does what I want. I’m trying to check if the compass ruby gem is installed on the remote machine and if it’s not, I want to install it. I added this line to the bottom of the script:

.
.
.
if [ `gem list compass -i` == 'false' ]
then
  echo -e "Compass not installed... Installing it now."
  gem install compass -V
fi


EOF

But `gem list compass -i`. is getting evaluated on my local machine beforehand (I have compass installed). Even running gem list compass -i in the script with no quotes to see the output is returning true which is incorrect. I tried escaping the command with a number of s but it didn’t work.

I guess two questions:

How is it that other commands in the script (mkdir, cd, git init etc…) work correctly on the remote machine but gem list does not?

How do I escape that command to run it remotely?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

The problem with your original code is that the command substitution expression (denoted by back-ticks) is evaluated prior to the execution of the ssh command. In a different situation you might consider quoting the here-doc keyword (e.g. “EOF”) in order to prevent parameter expansion in your here-doc, but in this case you actually do want to perform some parameter substitution client-side. So a solution here could be to escape the command substitution. Try this instead:

if [ `gem list compass -i` == 'false' ]
then
  echo -e "Compass not installed... Installing it now."
  gem install compass -V
fi

The escaped back-ticks prevent the command substitution from being evaluated.

I’ll also mention that the back-tick syntax for command substitution is widely considered to be a legacy feature and that the dollar-sign syntax is generally preferred nowadays. Here is what the above snippet would look like with the dollar-sign syntax instead:

if [ $(gem list compass -i) == 'false' ]
then
  echo -e "Compass not installed... Installing it now."
  gem install compass -V
fi

For more information about the differences between the two notations, you can refer to the following StackExchange posts:

You may also want to look at the GNU Bash manual page on command substitution.

And also at the GNU Bash manual page on redirection.

Note in particular the following subsection on here-docs:

3.6.6 Here Documents

This type of redirection instructs the shell to read input from the current source until a line containing only word (with no trailing blanks) is seen. All of the lines read up to that point are then used as the standard input (or file descriptor n if n is specified) for a command.

The format of here-documents is:

[n]<<[-]word
    here-document
delimiter

No parameter and variable expansion, command substitution, arithmetic expansion, or filename expansion is performed on word. If any part of word is quoted, the delimiter is the result of quote removal on word, and the lines in the here-document are not expanded. If word is unquoted, all lines of the here-document are subjected to parameter expansion, command substitution, and arithmetic expansion, the character sequence newline is ignored, and ‘’ must be used to quote the characters ‘’, ‘$’, and ‘`’.

If the redirection operator is ‘<<-’, then all leading tab characters are stripped from input lines and the line containing delimiter. This allows here-documents within shell scripts to be indented in a natural fashion.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x