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 
5
  • 2
    Have a look at BashFAQ/001, "How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?" Commented Jun 19, 2017 at 15:15
  • If you have bash 4+ you can use mapfile IFS= mapfile -t sshserver <"$serverlist" Commented Jun 19, 2017 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? Commented Jun 19, 2017 at 15:30
  • You should also look at PSSH, seems like it'd do a lot of what you want: linux.die.net/man/1/pssh Commented Jun 19, 2017 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 </dev/null) Commented Jun 20, 2017 at 5:31

1 Answer 1

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')
Sign up to request clarification or add additional context in comments.

2 Comments

Your gonna want the -t flag to readarray to remove the newlines from elements.
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!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.