Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm trying to run a set of commands on a remote machine, that includes an if statement. I'm using this to shutdown a list of kvm instances. The first line should be fine, but could be prettier, rest needs some help.

ssh root@kvmsrv 'virsh shutdown $host 2> /dev/null; virsh destroy $host 2> /dev/null; sleep 2; virsh undefine $host 2> /dev/null'

# Also needs to be run on remote machine
# to disconnect iscsi
iscsiadm -m session | grep $host
if [ $? == 0 ]; then
  iscsiadm -m node -T $stserver.$host -u
fi

# then on local machine
tid=`ssh root@storage1 'cat /proc/net/iet/volume' | grep $host | head -1 | awk '{print $1}' | awk -F: '{print $2}'`
if [ $tid ]; then
  echo "Deleting tid:$tid from $stserver."
  ssh root@$stserver "ietadm --op delete --tid=$tid"
fi

I guess I could do the same for the second portion, just separate it all with ; but if anyone goes to read my code later on they'd probably be scratching their heads...

Is there a way to format all this so its readable and still makes sense and have all the remote commands execute properly?

share|improve this question
add comment

4 Answers

  1. Put your long and complex sequence of commands in its own shell script, let's call it virsh-shutdown-remote.sh

  2. Run ssh and use input redirection to run the script:

    ssh root@kvmsrv < virsh-shutdown-remote.sh
    

Putting the commands in a script is a good idea in any case.

And, you did not ask for it, but here's a tip:

iscsiadm -m session | grep $host
if [ $? == 0 ]; then
  iscsiadm -m node -T $stserver.$host -u
fi

... can be written as a single line:

iscsiadm -m session | grep $host && iscsiadm -m node -T $stserver.$host -u
share|improve this answer
add comment

You can use HEREDOCS, e.g:

ssh root@kvmsrv <<EOF
  virsh shutdown $host 2> /dev/null
  virsh destroy $host 2> /dev/null
  sleep 2
  virsh undefine $host 2> /dev/null

  # to disconnect iscsi
  iscsiadm -m session | grep $host
  if [ \$? == 0 ] ; then
    iscsiadm -m node -T $stserver.$host -u
  fi
EOF

Please be aware that I escaped $? as otherwise it would be evaluated by your local shell and not from your remote shell. As $host seems to be defined locally you won't have to escape it.

Just a small comment though you didn't ask for it. You can remotely run virsh commands, without the need to explicitly ssh into the host, e.g:

virsh -c qemu+ssh://root@kvmsrv/system destroy host

will work. You also don't need ssh as libvirt allows you to authenticate with ssl certs insteads.

share|improve this answer
    
You forgot to escape his other variables, such as \$host, \$stserver. In fact it's better to write the whole thing as ssh root@kvmsrv <<"EOF" in which case you don't need to escape the $-s inside, and just use his script verbatim. –  janos Jun 17 '12 at 8:12
    
@janos as i said $host seems to be defined locally - the script never defines/get it somewhere. The same goes for $stserver. But i agree "EOF" is often better than escaping. –  Ulrich Dangel Jun 17 '12 at 15:55
    
Notice that he single-quoted his very first command, so at least there $host is defined on the remote side. In the end he uses $host again in a local context, but it would be wrong to assume they are the same. As per his second block of code, from the context I think it's intended to run remotely, using variables defined on the remote, but I agree this is not at all 100% clear. –  janos Jun 18 '12 at 4:56
add comment

Maybe just add commentary to explain things that (should be) obvious? I do this regularly in scripts to remind my own ignorant butt what I was up to when I wrote the [censored] thing in the first place.

share|improve this answer
add comment

Well, the simple answer is that it is actually possible to rewrite ssh root@kvmsrv 'cmd1; cmd2; cmd3' as:

ssh root@kvmsrv '
cmd1
cmd2
cmd3
'

The only thing to remember is that single quotes "inside" single quotes should be expressed as: '\''. Examples:

ssh localhost '
echo hi
whoami
ls -ld /
var="'\''"
echo "$var"
if [ $? == 0 ]; then
   echo "escaping single quote worked"
fi
'

# get single quote from file and print it
echo "'" > sqfile
ssh localhost '
#set -xv
echo hi
cat sqfile
var="$(cat sqfile)"
echo "$var"
'

# pass a single quote to the remote host and print it
# while keeping the outer single quotes for the ssh command
escsquote="'\''"
squote="'"
squote="'${squote//\'/${escsquote}}'" # bash

ssh localhost 'sh -c '\''
#set -xv
echo hi
echo "$1"
'\''' _ "$squote"
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.