DEV Community

Elliot Derhay
Elliot Derhay

Posted on

BASH function for printing IP addresses for domains

Updated to include a function alternative to the original snippet further down.


First of all, dang, it's been a while... 😅

Anyway, I was trying to find a one-off way to print a list of domains and each domain's main A record's IP address. After a little diging 😉 this is what I ended up with initially.

Snippet

#!/usr/bin/env bash
domains=(example.com example.net example.org)
for domain in "${domains[@]}"; do
    echo "$domain : $(dig +short a $domain | tail -n1)"
done
Enter fullscreen mode Exit fullscreen mode

Sample output

example.com: 93.184.216.34
example.net: 93.184.216.34
example.org: 93.184.216.34
Enter fullscreen mode Exit fullscreen mode

Explanation

BASH arrays

I'm sorry to say I don't really know much on the subject; the handful of times I've needed them in scripting, I've had to look up syntax for creating them and then accessing. This article seems to shed some light on the subject though, including how to iterate over array indices instead of only array elements.

dig command

As someone who comes from primarily being a Windows user (only due to work these days), I kept forgetting about this command. It lets you query any kind of DNS records for a domain.

It's also normally pretty verbose too, but passing it the +short option cuts down the output. a also tells it to only query A records.

tail command

I don't use this one often, but I have used head quite a bit to pull the first 10+ lines of a file if I was looking for some information stored at the top. This command pulls content from the bottom of a file (or output piped to it in this case).

Function alternative

After digging a bit more and chatting with some local Linux users, I ended up rewriting the above snippet into a function that did the same thing.

#!/usr/bin/env bash
function list_domain_ips() {
  while read domain; do
    echo "$domain: $(dig +short a $domain | tail -n1)" 
  done < $1
}
Enter fullscreen mode Exit fullscreen mode

Usage

Example 1: passing a filename

# function call
list_domain_ips example.txt
Enter fullscreen mode Exit fullscreen mode
# example.txt contents
example.com
example.net
example.org
Enter fullscreen mode Exit fullscreen mode

Example 2: passing /dev/stdin

list_domain_ips /dev/stdin <<< "example.com
example.net
example.org"
Enter fullscreen mode Exit fullscreen mode

Explanation

while instead of for...in loop

This was simpler because the loop will only run as long as the read command keeps supplying more input.

Last line of the loop: done < $1

This line is what's passing input to the loop. In this case, it's passing the first argument sent to the function, $1. If the function had second, third, fourth arguments (ad infinitum), they would be $2, $3, and $4, respectively. The first argument is also a filename containing a multi-line list of domains to check.

Using /dev/stdin as the argument

This is useful if, even though this function expects a filename, you still want to pass a list directly yourself. This part of the solution I found on a superuser answer. Through testing, I found that a blank line will result in undesirable output (just something I wanted to mention for any BASH beginners on here). To prevent this, the opening and closing quotes do need to be in contact with lines that need to be used in the loop.

Sample output with blank lines
: m.root-servers.net. # opening quote on its own line
example.com: 93.184.216.34
example.net: 93.184.216.34
example.org: 93.184.216.34
: m.root-servers.net. # closing quote on its own line
Enter fullscreen mode Exit fullscreen mode

Besides that minor issue, the output is formatted exactly the same way.

⚠️ Important note: I was told by a local Linux wizard 🧙 by the name of Jās Eckard that /dev/stdin isn't 100% portable.

Just be aware that using /dev/stdin is not portable across all Un*x. I just read yesterday that it's on Linux and OSX (and even then, symlinks to different files), but not necessarily other Un*x.

I just wanted to include this note from him for reference, in case this doesn't work for a particular user.

Summary

So initially I was iterating over an array of domain names, but the better solution ended up being the function since it takes either a filename or a multi-line list sent through /dev/stdin (and obviously since it's easier to store and call from CLI).

The old echo line using a subshell to run the dig command and piping the output to tail, and prefixing that output with the domain name itself for reference carried over without needing to be changed.

Thanks for reading, and enjoy! 🐧 💻


Useful links

Top comments (1)

Collapse
 
jsn1nj4 profile image
Elliot Derhay

Well... This article was intended to be a short one with a little bit of explanation... 😅