0

Want to run "for loop" from a hop server to a list of servers. If I run the for loop in individual server, it works fine but I don't know how to nest it and make it work from a hop server.

For loop output from individual host:

$ for i in {a..b}; do echo Volume: /dev/sd$i; sudo /usr/sbin/smartctl -a /dev/sd$i | egrep -i "model|serial"; done
Volume: /dev/sda
Device Model:     TOSHIBA THNSNJ256GCSU
Serial Number:    35FS109IT88W
Volume: /dev/sdb
Model Family:     Seagate Constellation ES.3
Device Model:     ST4000NM0033-9ZM170
Serial Number:    Z1Z7EK85
$ 

Below is how I usually run "for loop" from a hop server:

$ for i in `cat hostlist`;do echo $i;ssh $i "uptime";echo " ";done

Please suggest!

αғsнιη
  • 41,407
rajdyp
  • 13

1 Answers1

1

You are probably looking for something like:

while IFS= read -r host
do {
  printf "%s\n" "$host"
  ssh -t -- "$host" '
    for i in a b
    do
      printf "%s\n" "Volume: /dev/sd$i"
      sudo smartctl -a "/dev/sd$i" | grep -Ei "model|serial"
    done'
  } 0<&3
done 3<&0 <hostlist

I am assuming hosts are listed in the hostlist file, one per line. IFS= and -r are probably unnecessary here, because host names are unlikely to contain blank characters or backslashes; they should not hurt, though. Similarly, reading your hostlist in a for loop is probably fine in this case, but using while loops for that is a good habit. See Why does my shell script choke on whitespace or other special characters? for more on this.

For each host, ssh is invoked with the -t option to force the allocation of a pseudo-terminal on the remote host, needed to type in the password that sudo will ask you (unless you configured it not to).

A new file descriptor is opened (3<&0), duplicating that of the outer standard input, to make the latter available to the body of the loop (which is wrapped in { } for this reason). ssh would otherwise read from hostlist and be unable to interact with you (for instance, when sudo requires your password).

I replaced echo with printf because the latter is more robust (even if, again, it was not strictly necessary here). And I replaced egrep with grep -E because (looking at the GNU manual) the former is deprecated and only provided for backward compatibility.

Finally, I replaced the brace expansion ({a..b}) with a b to make the script able to run in any POSIX shell, including those that do not support that feature (e.g. dash).

fra-san
  • 10,205
  • 2
  • 22
  • 43