How can I resolve a hostname to an IP address in a Bash script?

  • What's the most concise way to resolve a hostname to an IP address in a Bash script? I'm using Arch Linux.

    Shame that the `getent ` answer is somewhere down there near the bottom. It's the simplest, requires no extra packages and is *easier* to parse from a Bash script, too.

    @0xC0000022L: The new shame is that that answer suggests `getent hosts somehost`, when running this *while on `somehost`* will produce an IPv6 address, which is different from how most other tools (`ping`, `ssh` at least) resolve names, and breaks some things. Use the `ahosts` instead of `hosts`.

    @j_random_hacker: who keeps you from requesting specifically IPv4 (`ahostsv4`) _or_ IPv6 (`ahostsv6`) addresses? Personally I find nothing wrong with the unspecific request returning IPv6. Your code should be prepared. IPv6 has been out there for more than 20 years now.

    @0xC0000022L: Nobody "keeps me" from doing that, but the answer specifically suggests `hosts`, and so far 4 people have upvoted vinc17's comment expressing the pain caused by "suddenly IPv6". Being prepared for IPv6 is not always the issue: many programs need a way to determine whether two names/addresses refer to the same host. They can either use simple string matching, or they must know a lot about the network to find the "true" answer. The latter is a minefield, so many 3rd-party programs and systems -- that I have no control over -- use the former.

  • Chris Down

    Chris Down Correct answer

    9 years ago

    You can use getent, which comes with glibc (so you almost certainly have it on Linux). This resolves using gethostbyaddr/gethostbyname2, and so also will check /etc/hosts/NIS/etc:

    getent hosts | awk '{ print $1 }'

    Or, as Heinzi said below, you can use dig with the +short argument (queries DNS servers directly, does not look at /etc/hosts/NSS/etc) :

    dig +short

    If dig +short is unavailable, any one of the following should work. All of these query DNS directly and ignore other means of resolution:

    host | awk '/has address/ { print $4 }'
    nslookup | awk '/^Address: / { print $2 }'
    dig | awk '/^;; ANSWER SECTION:$/ { getline ; print $5 }'

    If you want to only print one IP, then add the exit command to awk's workflow.

    dig +short | awk '{ print ; exit }'
    getent hosts | awk '{ print $1 ; exit }'
    host | awk '/has address/ { print $4 ; exit }'
    nslookup | awk '/^Address: / { print $2 ; exit }'
    dig | awk '/^;; ANSWER SECTION:$/ { getline ; print $5 ; exit }'

    By default, using dig only works with ipv4, where host gives both ipv4 and ipv6 answers. This might be unexpected. You can try `host`, `dig +short`, `host`, `dig +short`, `host`, `dig +short`.

    Also note that you may want to use `dig +search` if you want to reproduce `host` command more closely

    DIG does not work, if is a CNAME it will not return the IP.

    Sometimes, `host` can be timed out and returns nothing. For some domains, `dig +short` may return domain alias in the first line. So, to ensure the output is an IPv4 address, use `dig +short | grep -Eo '[0-9\.]{7,15}' | head -1`.

    When I `dig` with an `http` protocol added, it finds `SOA`. When I `dig` without the `http` protocol, it comes with the A record. What does this mean? Why does dig change depending on http protocol?

    `host` prints error output to `stdout`, `dig` also seems to return `0` for unresolved hosts, `getent` doesn't seem to allow a timeout... I'm surprised this is so complicated.

    In the case where `` is a CNAME record, I found that `dig +short` will return the referenced DNS name instead of the IP address, whereas `getent hosts` will always return the IP address.

    There's a big difference between "ask the OS to resolve a host" and "run this program which will use its internal logic to query DNS". I'm fairly sure that nslookup & dig are in the latter category, though I don't know about 'host'. For example, what if the host is defined in /etc/hosts?

    @tomwhipple For the purposes of this question, the distinction seems not particularly important. However, I will separate this answer out to differentiate functions using the OS resolver vs. their own means.

    Using `getent hosts ` is incorrect, as for instance it may give an IPv6 address while IPv6 doesn't work. The correct solution is to use `getent ahosts ` to try both IPv6 and IPv4 if needed.

    Worth mentioning: host, dig and nslookup seems to directly talk to the servers listed in resolv.conf, whereas "getent hosts" respect both the local hosts file and library-level caching (such as nscd) if enabled.

    `dig +short | awk '/^[0-9]+\./ { print ; exit }'` considers CNAMEs.

    Thank you so much for giving us an answer that doesn't require `dig` or `host`, which isn't available on all flavors of Linux (including some particularly sparse Docker images)

    I can resolv avahi-hosts by using getent method (only this method)

    Thank you very much

    You can use `$(dig +short | tail -1)` to only take the last line of output of the command (in my testing it has always been an IP address and never a hostname, but I think this shouldn't be relied upon). Going the other way, for more robust checking for IPv4 address, you can build upon luissquall's awk command. I'm aware I'm being a bit pedantic, but that one only checks the first character. This checks whole lines: `awk '/^([0-9]{1,3}\.){3}[0-9]{1,3}$/ { print ; exit }` ... Match 1 to 3 digits followed by a dot, all that three times, then 1 to 3 digits, with nothing else after.

    That was my problem too, after reviewing every config file and comparing it with the other virtual server i didn't found anything, till i look the /etc/hosts. Noob fail i suppose.thanks!

License under CC-BY-SA with attribution

Content dated before 6/26/2020 9:53 AM