I have a query.sh script which runs dig commands, performing a set of lookups from different DNS servers, which are currently given in a column in the single input file used (sites.txt).
My goal is to modify this script to use a different input file, dns_servers.txt, to find the DNS servers to iterate through for each query.
I'm not clear on where to start here. What do I need to do to be able to safely nest while read loops?
#!/bin/sh
while read line;
do
        set $line
        echo "SITE:" $1@$2
        /usr/sbin/dig +short -4 @$2 $1
        sleep 5
        exitStatus=$?
        echo "Exit Status: " $exitStatus
done < sites.txt
Current format has a hostname and a DNS server to use for lookups against that hostname.
www.google.com 8.8.4.4
The intent is for the column with the DNS server to be ignored, and the contents of dns_servers.txt to be used instead.
10.1.1.1
12.104.1.232
...
                Nested loop definition That is to say, it is a loop that exists inside an outer loop. When you integrate nested loops in bash scripting, you are trying to make a command run inside another command. This is what it means: a bash nested for loop statement runs a command within another loop.
There are three basic loop constructs in Bash scripting, for loop, while loop , and until loop .
The bash while loop is a control flow statement that allows code or commands to be executed repeatedly based on a given condition. For example, run echo command 5 times or read text file line by line or evaluate the options passed on the command line for a script.
Ignoring any additional column(s) in the sites.txt file, and iterating through the lines of dns_servers.txt, might look like the following:
#!/bin/sh
while read -r site _ <&3; do
  while read -r dns_server <&4; do
    dig +short -4 "@$dns_server" "$site"; exit=$?
    sleep 5
    echo "Exit status: $exit"
  done 4<dns_servers.txt
done 3<sites.txt
The key changes here:
read. The underscore passed as second positional argument to the first read is the variable name to which the second column of site.txt is now being saved.3 and 4) for outer and inner loops to keep them separated.Incidentally, if you were targeting bash (#!/bin/bash) rather than POSIX sh (#!/bin/sh), I might do this differently. The below uses the bash 4 extension mapfile to read dns_servers.txt all at once:
#!/bin/bash
readarray -t dns_servers <dns_servers.txt
while read -r site _; do
  for from_ip in "${dns_servers[@]}"; do
    dig +short -4 "@$from_ip" "$site"; exit=$?
    sleep 5
    echo "Exit status: $exit"
  done
done <sites.txt
Here, we read dns_servers.txt only once, and reuse that list of values for each value read from sites.txt.
If you're using bash 3.x, mapfile can be replaced with a loop:
dns_servers=( )
while read -r; do dns_servers+=( "$REPLY" ); done <dns_servers.txt
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With