tags:

views:

95

answers:

2

I'm writing a script to ssh in to a list of machines and compare a variable to another value.. I've run into a problem (I have a couple workarounds, but at this point I'm just wondering why this method isn't working).

VAR=`ssh $i "awk -F: '/^bar/ {print \$2}' /local/foo.txt"`

($i would be a hostname. The hosts are trusted, no password prompt is given)

Example of foo.txt:

foo:123456:abcdef
bar:789012:ghijkl
baz:345678:mnopqr

I'm assuming it's a problem with quotes, or \'s needed somewhere. I've tried several methods (different quoting, using $() instead of ``, etc) but can't seem to get it right. My script is working correctly using the following:

VAR=`ssh $i "grep bar /local/foo.txt" | awk -F: '{print \$2}'`

Like I said, just a curiousity, any response is appreciated.

Forgot to post what my output was: awk is spitting out the whole matched line, not the 2nd section. Playing with the quotes and \'s a bit I seemed to get an error about "{print " command not found etc, as if there was a new line in there somewhere.

+5  A: 

sshd gives your command to bash to execute, so it'll go through the bash interpreter on the remote side as well as the side you're executing the script on. Let's look at your command:

VAR=`ssh $i "awk -F: '/^bar/ {print \$2}' /local/foo.txt"`

You've properly escaped the $2 for your local machine so that the bash script you're executing does not interpret it. But all the quotes are being removed by the time it gets to awk (I'm not entirely sure why the internal quotes get removed) and it's executing this:

awk -F: /^bar/ {print $2} /local/foo.txt

bash on the remote side sees $2 and replaces it with an empty string, leaving you with this:

awk -F: /^bar/ {print } /local/foo.txt

That's why it prints the entire line. So how do you fix it? You can escape what bash on the remote side will be executing with a slash, like so:

VAR1=`ssh $i localhost "echo awk -F: '/^bar/ {print \\\$2}' /local/foo.txt"`

Also, you can just echo the command to see what bash is really executing for you to debug any further problems you come across:

VAR1=`ssh $i localhost "echo awk -F: '/^bar/ {print \$2}' /local/foo.txt"`
echo VAR1: $VAR1

Execute it and see this output and see right away that it has removed $2:
VAR1: awk -F: /^bar/ {print } /local/foo.txt
indiv
It is not that the quotes are being arbitrarily removed, but that the shell on the remote side is interpreting them. Write the command line. Quote it for the remote shell. Quote it for the local shell.
Chris Johnsen
Ahhh I was close! Thank you!
Kyle
@Chris Johnsen: I had confused myself while experimenting when I passed `"...\'{print \$2}\'.."`. I was seeing on the remote side that it properly had `'` around the expression, but the `$2` was still missing. But after reading what you said it makes sense because it is replacing the `\'` with `'` at the same time it substitutes `$2`. I knew it wasn't magic, I just couldn't explain it right away. ;) Thanks for clarifying.
indiv
A: 

try to use the $() syntax as far as possible

VAR=$(ssh $i "awk -F: '/^bar/ {print \$2}' /local/foo.txt")
ghostdog74