I am trying to write a scrip that will collect the hostname, IP and total memory installed on remote hosts from a list I feed into the script. The script will collect information from Redhat and Solaris machines.Below is what my script looks like:

#!/bin/bash
echo > ip_info.output
echo -e "\n"
for host in `cat ip_adds`
do
echo "Hostname:" $host
sudo ssh -o BatchMode=yes -o ConnectTimeout=5 $host "echo IP Address:; ip route get 1 | awk '{print $NF;exit}'; free -m | grep Mem | awk '{print $1,$2}'"
echo -e "\n"
done

When I run the script I get error below:

awk: {print ,}
awk:        ^ syntax error
awk: {print ,}
awk:         ^ syntax error
awk: cmd. line:1: {print ,}
awk: cmd. line:1:          ^ unexpected newline or end of string

I think the problem is with free -m | grep Mem | awk '{print $1,$2} but not sure how to rectify it. If I run free -m | grep Mem | awk '{print $1,$2} directly into the shell I have no issues. Just inside the script.

New contributor
user315468 is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
  • What is the echo > ip_info.output doing? – terdon Oct 12 at 8:55
  • The echo > ip_info.output is writing nothing to the output file so that if I have to run the script again for whatever reason I dont end up with duplicate information. – user315468 Oct 12 at 9:04
  • Yes, but you don't seem to be using the output file anywhere, so I assume you're running the script as script.sh > ip_info.output, right? – terdon Oct 12 at 9:07
  • no Im running it as ./script.sh | tee -a ip_info.output. echo > ip_info.output clear the file for when ./script.sh | tee -a ip_info.output is run. – user315468 Oct 12 at 9:14
  • 1
    OK, then don't use -a. The -a tells tee to append to the file instead of overwriting it. If you use ./script.sh | tee ip_info.output, then you'll still see the output in the terminal and you'll also save it to ip_ifo.output, overwriting anything that was already in the file. – terdon Oct 12 at 9:50

This is considerably more complicated than it needs to be. Also, why would you run ssh with sudo? If you need to log into the remote as root, then you can do that (ssh root@$host) but it's very unlikely you would need to run ssh with sudo unless your ssh keys all belonged to root. Which is a pretty bad idea.

Also, on my Arch system, the command you seem to be using to get the IP returns the UID of my user:

$ ip route get 1
1.0.0.0 via 192.168.1.1 dev enp0s31f6 src 192.168.1.111 uid 1000 
    cache 
$ ip route get 1 | awk '{print $NF;exit}'; 
1000

It does work as expected on an Ubuntu I tested:

$ ip route get 1
1.0.0.0 via 123.456.7.8 dev eth0  src 123.456.7.9
$ ip route get 1 | awk '{print $NF;exit}'; 
123.456.7.9

So perhaps a more portable version of this is to print the field after src:

$ ip route get 1 | sed -nE 's/.* src ([0-9.]+).*/\1/p'
192.168.1.111

The errors you saw were indeed because of quoting. Since you were running ssh $host "command", the double quotes around command cause the shell to expand any variables found inside the command (so things like awk's $2 etc). To avoid this and pass the symbols unexpanded to awk, you need to escape the $.

A simpler version of your script:

#!/bin/bash
sshOpts="BatchMode=yes -o ConnectTimeout=5"
echo > ip_info.output
echo ""                
while read host; do
    printf "Hostname:%s" $host
    ssh -o $sshOpts $host "printf 'Hostname: %s\nIP: %s\nMem: %s\n' $host "$(ip route get 1 | sed -nE 's/.* src ([0-9.]+).*/\1/p')" "$(free -m | awk '/Mem/{print $2}')""
done < ip_adds
  • Thanks for this terdon - Your script looks simpler however when I run it I am getting: Hostname:eXX-XX-XX-XXXXX-01Hostname: eXX-XX-XX-XXXXX-01 IP: eth0 Mem: 3832 – user315468 Oct 12 at 9:33
  • Seems that the IP isnt being collected properly. – user315468 Oct 12 at 9:36
  • @user315468 yes, the output of ip route get 1 can change on different systems. Try the updated answer, sorry! – terdon Oct 12 at 9:54
  • thanks for your input. Much appreciated. With your help I have modified my script and now I get a really nice and neat output. My script looks like: #!/bin/bash echo > ip_info.output echo -e "\n" for host in cat ip_adds1` do sudo ssh -o BatchMode=yes -o ConnectTimeout=5 $host "printf 'Hostname: %s\nIP: %s\nMem: %s\n' $host "$(ip route get 1 | sed -nE 's/.* src ([0-9.]+).*/\1/p')" "$(free -m | awk '/Mem/{print $2}')"" echo -e "\n" done` Out put is now: Hostname: eXX-XX-XX-XXXXX-XX IP: XX.XX.XX.XXX Mem: 3832 – user315468 Oct 12 at 10:44
  • 1
    @user315468 please consider incorporating the other changes I've made. The while read ... < file loop is safer than the for and a better way to parse files in general and the echo -e "\n" is just a more complicated way of writing echo "", there's no reason to use it. In fact, it would be even simpler to not use echo at all and just add a \n to the beginning of the printf command, but that's up to you. – terdon Oct 12 at 10:51

I have found an answer for this. It was to do with escaping so I added \ before $1 and $2 as per below:

free -m | grep Mem | awk '{print \$1,\$2}
New contributor
user315468 is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

Your Answer

user315468 is a new contributor. Be nice, and check out our Code of Conduct.
 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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