create an array of multiple multi-line text for script to use..

Rob

Administrator
Staff member
Joined
Oct 27, 2011
Messages
1,210
Reaction score
2,240
Credits
3,485
So, main purpose of this is so a QA guy can run this script to update /etc/hosts on one of the qa-test VMs to ensure they're hitting the correct cluster of hosts.. I grabbed most of this from two stackexchange answers:

The /etc/hosts stuff:
https://unix.stackexchange.com/questions/60549/etc-hosts-file-refer-to-another-configuration-file

The part listing out files to use to insert:
https://askubuntu.com/questions/682095/create-bash-menu-based-on-file-list-map-files-to-numbers

Currently, the script looks in /etc/hosts.d/ and creates a list of available files to insert into /etc/hosts and replace the old content between two markers..

example of one of the hosts.d files - this one would be called 'westus-prod'
Code:
111.222.333.444     app1.domain.com     # westus-prod
111.222.333.444     app2.domain.com     # westus-prod

It works great!

However, I would instead rather have the user pick from a list of options that are contained in the script itself instead of maintaining all the different /etc/hosts.d files..

I probably just need to think harder here, i'm sure something like this would work, but i'm blanking on listing the choices and inserting them into the /etc/hosts file part.. :
Code:
westus-prod=(
111.222.333.444 app1.domain.com #westus-prod
111.222.333.444 app2.domain.com #westus-prod
);

centralus-prod=(
222.111.222.333 app1.domain.com #centralus-prod
222.111.222.333 app2.domain.com #centralus-prod
);

Here's the script
Code:
#!/bin/bash

files=( /etc/hosts.d/*)
shopt -s extglob

string="@(${files[0]}"
for((i=1;i<${#files[@]};i++))
do
    string+="|${files[$i]}"
done
string+=")"

select file in "${files[@]}" "quit"
do
    case $file in
    $string)
sudo cp /etc/hosts "/etc/hosts.bak.$(date +%Y%m%d%H%M%S)" && \
    (
        sed -n '1,/^# CUSTOM BEGIN/{/^# CUSTOM BEGIN/!p;}' /etc/hosts; \
        echo "# CUSTOM BEGIN"; \
        cat "$file"; \
        echo "# CUSTOM END"; \
        sed -n '/^# CUSTOM END/,${/^# CUSTOM END/!p;}' /etc/hosts; \
    ) | \
    sudo tee /etc/hosts.new | \
    sed -n '/^# CUSTOM BEGIN/,/^# CUSTOM END/p' && \
        sudo mv /etc/hosts.new /etc/hosts

        break;
        ;;
  
    "quit")
        exit;;
    *)
        file=""
        echo "Please choose a number from 1 to $((${#files[@]}+1))";;
    esac
done
 
Last edited:


Working from the bottom up.. still would need to figure out how the user can select from a list of arrays, but this kind of works to print them out, which splits into two lines, but creates a space before the 2nd line..

I guess i could put them into a tmp file, then use sed or something to remove beginning white space?

Code:
#!/bin/bash

westus_prod=(
111.222.333.444 app1.domain.com \# westus_prod\\n
111.222.333.444 app2.domain.com \# westus_prod
);

centralus_prod=(
222.111.222.333 app1.domain.com \# centralus_prod\\n
222.111.222.333 app2.domain.com \# centralus_prod
);

( IFS=$'\n'; echo -e "${centralus_prod[@]}" )
 
Last edited:
Meh - i think i'll maybe create the files at the top of the script, then display them, let the user choose, once everything is done, clean them up.

Still a fun script if someone can figure out how to choose from the arrays, update /etc/hosts a bit cleaner lol :)
 
I'm not completely understanding what you're up to... But to chose elements from an array I've just written:

Bash:
count=0
for $i in $array; do echo $i; count=$(($count+1)); done | nl
printf "Choose the element with a number: "
read -l choice

# Check if a number
[ "$choice" -eq "$choice" 2>/dev/null ] || echo "Not a num"
# Check if admitted number
[ "$choice" -le 0 ] || [ "$choice" -gt "$count" ] || echo "Out of bound"

filter="${choice}q;d"
line=$( for $i in $array; do echo $i; done | sed $filter )

# This is the array element chosen
echo $line

Edit some stuff and give it a try ;).

I would like to understand what you want to do better in order to write a clean version in POSIX sh.
 


Top