2

I am currently running a script that uses nslookup on a bunch of hosts and then uses awk to print desired lines into a table. I am printing one line to file1 and another to file2, then using paste file1 file2 >> file3 to produce this table.

The table looks like this

Host   IP
name  10.10.10.10
name  10.10.10.10
name 10.10.10.10

For the most part, this is working. But for some reason, about 20 of my 160 results are getting "answer:" in the left column, and the hostname is appearing in the right. Like this:

Host IP
answer:  hostname

This is showing up randomly throughout the results and I can't figure it out because the nslookup doesn't have the word "answer:" in it anywhere for the script to accidentally awk.

Here is my script for reference:

hosts='hosts.list'
filelines=`cat $hosts`

Empty_Containers(){
        truncate -s 0 tmp.txt
        truncate -s 0 file1
        truncate -s 0 file2
}

for h in $filelines ;
do
        Empty_Containers
        nslookup $h > tmp.txt
        if grep -q "NXDOMAIN" tmp.txt
        then
                cat tmp.txt | awk 'FNR ==4 {print$5}' > file1
                echo "Did_Not_Resolve" > file2
                paste file1 file2 >> i.txt
        else
                cat tmp.txt | awk 'FNR ==4 {print$2}' > file1
                cat tmp.txt |awk 'FNR ==5 {print$2}' > file2
                paste file1 file2 >> i.txt
        fi
        cat i.txt | column -t 2 i.txt
done
  • 1
    Is there some reason you're not just using one awk script to print the output you desire rather than this Rube Goldberg machine? – DopeGhoti Jun 1 '18 at 18:07
  • @DopeGhoti Probably because I couldn't figure out how to awk 2 separate outputs. I figured out my problem, but I wouldn't mind if you showed me a better way to do it. – mitchelwith1el Jun 1 '18 at 18:14
  • This doesn't even use awk; I was able to just do for h in $(cat hosts.list); do a=$(dig +short $h | head -n1); echo -e "$h\t${a:-Did Not Resolve}"; done to seemingly get your desired result. – DopeGhoti Jun 1 '18 at 18:21
  • Welp. that replaced all my work pretty easily. Could you explain your script? also, I'm still getting the same "answer:" problem with it due to an extra line in the nslookup that says "Non-authoritative answer". How would you fix that? – mitchelwith1el Jun 1 '18 at 18:57
  • I went into detail in my answer. If you have further questions, I'm happy to explain them. – DopeGhoti Jun 1 '18 at 19:07
1

If your desired goal is to just make a table of hostnames and IP addresses, and you don't care particularly about using nslookup, I was able to seemingly create your desired output with a quick for .. echo loop:

for h in $( cat hosts.list ); do
    a=$(dig +short $h | head -n1)
    echo -e "$h\t${a:-Did_Not_Resolve}"
done

dig is a slightly more friendly-to-scripting DNS tool than is nslookup, using the +short option makes the output even cleaner. The output of a request for which there is no record is an empty string, so I use the built-in bash default parameter expansion (${var:-default}) to handle the case of no record giving a "default" answer of Did_Not_Resolve.

$ dig www.example.com

; <<>> DiG 9.10.6 <<>> www.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23579
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4000
;; QUESTION SECTION:
;www.example.com.       IN  A

;; ANSWER SECTION:
www.example.com.    20308   IN  A   93.184.216.34

;; Query time: 28 msec
;; SERVER: 172.28.8.1#53(172.28.8.1)
;; WHEN: Fri Jun 01 12:02:27 MST 2018
;; MSG SIZE  rcvd: 60

$ dig +short www.example.com
93.184.216.34

The ultimate yield is this output:

www.example.com 93.184.216.34
www.google.com  172.217.14.68
host.doesnotexist.tld   Did_Not_Resolve
unix.stackexchange.com  151.101.129.69

An alternative to dig is also host:

$ for h in $(cat hosts.list); do host $h; done
www.example.com has address 93.184.216.34
www.example.com has IPv6 address 2606:2800:220:1:248:1893:25c8:1946
www.google.com has address 216.58.193.196
www.google.com has IPv6 address 2607:f8b0:4007:80d::2004
Host host.doesnotexist.tld not found: 3(NXDOMAIN)
unix.stackexchange.com has address 151.101.129.69
unix.stackexchange.com has address 151.101.1.69
unix.stackexchange.com has address 151.101.65.69
unix.stackexchange.com has address 151.101.193.69

In response to the questions in the comment below:

The only option I use for dig is +short, which reduces the output to either the IP address for the given host, or an empty string otherwise. I run dig in a subshell ($( dig [...] )) because I am capturing its output and assigning it to the variable a (for "address"). I am piping the output of dig through head -n1 as some hosts (like the host unix.stackexchange.com return multiple IP addresses; for the sake of simplicity, I simply grab the first one.

The reason this is being pulled out into a variable is so that we can use a simple parameter expansion trick to provide the "Did not resolve" text in lieu of an empty string, as described previously herein.

Expanding as requested on the echo statement specifically:

echo -e "$h\t${a:-Did_Not_Resolve}"
  • The -e switch tells echo that I will be using escape sequences. In this case, I am using \t which, when combined with -e, becomes a Tab rather than a literal escaped t.
  • $h is, as you would expect, simply replaced with the contents of the variable h.
  • \t, as explained earlier, becomes a Tab.
  • ${a:-Did_Not_Resolve}. Ah, here's where the magic is. bash has the ability when doing parameter expansion to do a little introspection as part of the process. The syntax ${var:-default} expands to the contents of the variable var or, if that is either unset or null, the provided replacement (in this example case, default; or in the actual use case here, Did_Not_Resolve). You can find more details about this in the bash manual page, in the section labeled "Parameter Expansion".

The end result of this is outputting on each line, in the following order, the hostname, a Tab, and either the address if there was one, or the text Did_Not_Resolve if there was not.

  • Thanks, this is very helpful. You can probably tell I'm a bash beginner, so could you explain your dig options to me better? particularly the "head -n1" and the need for a=$(...) – mitchelwith1el Jun 4 '18 at 17:15
  • Scratch that, I've figured that stuff out. Can you explain your syntax in the echo command further? – mitchelwith1el Jun 5 '18 at 12:13
  • I have gone into detail about the particulars of the echo invocation. – DopeGhoti Jun 5 '18 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.