9

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?


Current inputs:

query.sh

#!/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

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.


Desired Inputs

dns_servers.txt

10.1.1.1
12.104.1.232
...
8
  • Also, set $line is very, very buggy (look at what happens if site.txt contains a line with *). Use a real array, and read -r -a instead. Though, for only two items, you don't even need that: while read -r site_name destination_ip will put what's currently $1 in site_name and what's currently $2 in destination_ip. Commented Aug 3, 2015 at 15:40
  • 1
    while read name ip;, then drop the set command and use $name and $ip in place of $1 and $2. Also, exitStatus is the exit status of sleep, not dig; you need to save the value of $? immediately after the command whose status you want. Commented Aug 3, 2015 at 15:41
  • BTW, your tag is bash, but your shebang is #!/bin/sh. Bash scripts must use #!/bin/bash; the shebang #!/bin/sh is for POSIX sh, and any script using it is not guaranteed to have access to features not promised in the POSIX shell specification. Commented Aug 3, 2015 at 15:52
  • Also, I'd suggest running your scripts through shellcheck.net and fixing errors that finds before presenting them here. Commented Aug 3, 2015 at 15:55
  • The intent of the script was to verify that no matter wherever the user is located, he is be able to Query Websites and the websites perform correct DNS lookup. Commented Aug 3, 2015 at 17:03

1 Answer 1

12

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:

  • Pass the list of fields you want to parse as arguments to 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.
  • Nest your loops, since you want to read from the inner loop for every pass of the outer loop.
  • Use a different file descriptor (here, 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
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. The first fix worked. Second one gave me a readarray: command not found error, but that was because of the old bash version.
The output also was as expected.
Thanks Charles for editing the Question. It seems that the entire format of the question was messed up after posting.
I'm no longer afraid of nested loops in Bash! But now it seems I need to learn about file descriptors to really grok it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.