0

I'm trying to start using read -r, but no luck so far. The following script (added below) should make a list of SSH servers from /etc/hosts, and then execute the command. I use it for simple administration things, adding users, etc.

I normally use sshservers=($(<serverlist.txt)), but I ran my script through Shellcheck last week, and it said I should use read -r in stead. So I added that, but now my script gets stuck when I run it.

Is someone able to help me out how I should properly use read -r in stead? (And if you have any further tips or notes, please let me know, I'm still learning Bash, as you might see by looking at my script hehe).

Thanks in advance!

#!/bin/bash
serverlist=/home/demo/serverlist.txt
: > "$serverlist"
sed -e '/^#/d' /etc/hosts | awk '{print $2}' >> "$serverlist"
sed -i -- '/^localhost/ d' "$serverlist"
#sshservers=($(<serverlist.txt))
sshservers=$(read serverlist)
for sshserver in "${sshservers[@]}"
        do
        ssh -t demo@"$sshserver" "hostname && sudo ls /root/"
done
echo "done"

EDIT: /home/demo/serverlist.txt contains IP's with the following format, not sure if it helps:

192.168.1.1
192.168.1.2
192.168.1.3 
Florius
  • 367
  • 1
  • 5
  • 17
  • 2
    Have a look at [BashFAQ/001](http://mywiki.wooledge.org/BashFAQ/001), "How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?" – Benjamin W. Jun 19 '17 at 15:15
  • If you have bash 4+ you can use mapfile `IFS= mapfile -t sshserver <"$serverlist"` – 123 Jun 19 '17 at 15:18
  • @BenjaminW. thank you for your help. I'm not sure how to add this exactly to my script. I have to remove the `for` line and make it `while IFS= read -r sshserver; do`? – Florius Jun 19 '17 at 15:30
  • You should also look at PSSH, seems like it'd do a lot of what you want: https://linux.die.net/man/1/pssh – Jess Jun 19 '17 at 20:21
  • There isn't really any need to read the hosts into an array. Your sed | awk | sed -i could be refactored to a single Awk script which pipes into `while read -r`. Just take care to not let anything inside the loop consume your standard input (hint: `ssh – tripleee Jun 20 '17 at 05:31

1 Answers1

2

With older versions of bash (if you want the lines in an array):

sshservers=()
while read -r servername; do
    sshservers+=("$servername")
done < "$serverlist" 

In bash 4+ you can use readarray:

sshservers=()
readarray sshservers < "$serverlist"

Or in this case if you don't really need the servernames in a file, you could just loop over the results for the commands like so:

while read -r sshserver: do
    ssh -t "demo@$sshserver" "hostname && sudo ls /root/"
done < <(sed -e '/^#/d' /etc/hosts | awk '{print $2}' | grep -vE '^$|^localhost')
Olli K
  • 1,720
  • 1
  • 16
  • 17
  • Your gonna want the `-t` flag to readarray to remove the newlines from elements. – 123 Jun 19 '17 at 17:01
  • Hmm I'm not sure if I understand the first one, and how to use it in my situation. It would replace `sshservers=$(read serverlist)` only? But I really like the third option you provided, not using a txt file at all! I'll see if I can get that working, thank you! – Florius Jun 20 '17 at 08:08