Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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

share|improve this question

13 Answers 13

up vote 70 down vote accepted

As Heinzi said below, the best way is to use dig with the +short argument.

dig +short unix.stackexchange.com

If +short is unavailable for some reason, any one of the following should work:

host unix.stackexchange.com | awk '/has address/ { print $4 }'
nslookup unix.stackexchange.com | awk '/^Address: / { print $2 }'
dig unix.stackexchange.com | 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 unix.stackexchange.com | awk '{ print ; exit }'
host unix.stackexchange.com | awk '/has address/ { print $4 ; exit }'
nslookup unix.stackexchange.com | awk '/^Address: / { print $2 ; exit }'
dig unix.stackexchange.com | awk '/^;; ANSWER SECTION:$/ { getline ; print $5 ; exit }'
share|improve this answer
1  
+1 for showing how to solve the "more than one IP" issue. –  Heinzi Sep 15 '11 at 18:56
2  
+1 That toughs me a great example for awk as well –  rahmanisback Sep 15 '11 at 23:12
2  
+1 for using dig. host is nice, but it's also nice to have options. –  alesplin Sep 21 '11 at 2:12
2  
By default, using dig only works with ipv4, where host gives both ipv4 and ipv6 answers. This might be unexpected. You can try host www.google.com, dig +short www.google.com, host ipv6.google.com, dig +short ipv6.google.com, host www.facebook.com, dig +short www.facebook.com. –  jfgagne Sep 21 '11 at 15:21
4  
+1 for using a real "scriptable" command (dig +short) which only ouputs the IP address without that chatty human output "X has address Y"... –  Totor Mar 26 '13 at 22:43

With host from the dnsutils package:

$ host unix.stackexchange.com
unix.stackexchange.com has address 64.34.119.12

(Corrected package name according to the comments. As a note other distributions have host is different packages: Ubuntu bind9-host, openSUSE bind-utils, Frugalware bind.)

share|improve this answer
4  
Did you mean dnsutils? Anyway, host worked nice, thanks –  eugene y Sep 15 '11 at 14:55
    
You're probably right. I have no Arch here to check. (Intended to append a comment later mentioning this, but the answer was already upvoted so I supposed I nailed it...) –  manatwork Sep 15 '11 at 15:06
1  
See the resolveip entry below if you need to resolve something not in DNS (e.g. /etc/hosts) –  Gavin Brock Jul 2 '12 at 8:56
1  
Be aware that host sometimes returns multi-line output (in the case of redirects), you'll want host unix.stackexchange.com | tail -n1 if you just want the line with the IP address. –  Edward Coffey Jan 23 '13 at 5:04
    
There are multiple versions of "host" with different output formats. E.g. most systems seem to have the BIND9 version, but my Ubuntu 10.04 LTS server has some completely different version somehow.. –  ColinM May 22 at 19:51

I have a tool on my machine that seems to do the job. The man page shows it seems to come with mysql... Here is how you could use it:

resolveip -s unix.stackexchange.com
64.34.119.12

The return value of this tool is different from 0 if the hostname cannot be resolved :

resolveip -s unix.stackexchange.coma
resolveip: Unable to find hostid for 'unix.stackexchange.coma': host not found
exit 2

UPDATE On fedora, it comes with mysql-server :

yum provides "*/resolveip"
mysql-server-5.5.10-2.fc15.x86_64 : The MySQL server and related files
Dépôt         : fedora
Correspondance depuis :
Nom de fichier      : /usr/bin/resolveip

I guess it would create a strange dependency for your script...

share|improve this answer
3  
This seems to be the only solution on here that uses the OS's build in resolver - so works for /etc/hosts as well as DNS. –  Gavin Brock Jul 2 '12 at 8:57
    
Great, just what I needed - something that pays attention to /etc/hosts. –  Xiong Chiamiov Feb 23 '13 at 3:21

The following command using dig allows you to read the result directly without any sed/awk/etc. magic:

$ dig +short unix.stackexchange.com
64.34.119.12

dig is also included in the dnsutils package.


Note: dig has a return value of 0, even if the name could not be resolved. Thus, you'd need to check if the output is empty instead of checking the return value:

hostname=unix.stackexchange.com

ip=`dig +short $hostname`

if [ -n "$ip" ]; then
    echo IP: $ip
else
    echo Could not resolve hostname.
fi

Note 2: If a hostname has multiple IP addresses (try debian.org, for example), all of them will be returned. This "problem" affects all of the tools mentioned in this question so far:

share|improve this answer

The solutions given so far mostly work in the simpler case: the hostname directly resolves to a single ip address. This might be the only case where you need to resolve hostnames, but if not, bellow is a discussion on some cases that you might need to handle.

Chris Down and Heinzi shortly discussed the case where the hostname resovles to more than one ip addresses. In this case (and others bellow), basic scripting under the assumption that a hostname directly resolves to a single ip address may break. Bellow an example with a hostname resolving to more than a single ip address:

$ host www.l.google.com
www.l.google.com has address 209.85.148.147
www.l.google.com has address 209.85.148.103
www.l.google.com has address 209.85.148.99
www.l.google.com has address 209.85.148.106
www.l.google.com has address 209.85.148.105
www.l.google.com has address 209.85.148.104

But what is www.l.google.com? This is where the alias case need to be introduces. Lets check the example bellow:

$ host www.google.com
www.google.com is an alias for www.l.google.com.
www.l.google.com has address 74.125.39.103
www.l.google.com has address 74.125.39.147
www.l.google.com has address 74.125.39.105
www.l.google.com has address 74.125.39.99
www.l.google.com has address 74.125.39.106
www.l.google.com has address 74.125.39.104

So www.google.com does not directly resolve to ip addresses, but to an alias that itself resolves to a ip addresses. For more information on aliases, check here. Of course, the case where an alias has a single ip address is possible as shown bellow:

$ host g.www.ms.akadns.net
g.www.ms.akadns.net is an alias for lb1.www.ms.akadns.net.
lb1.www.ms.akadns.net has address 207.46.19.190

But can aliases be chained ? The answer is yes:

$ host www.microsoft.com
www.microsoft.com is an alias for toggle.www.ms.akadns.net.
toggle.www.ms.akadns.net is an alias for g.www.ms.akadns.net.
g.www.ms.akadns.net is an alias for lb1.www.ms.akadns.net.
lb1.www.ms.akadns.net has address 207.46.19.254

$ host www.google.fr
www.google.fr is an alias for www.google.com.
www.google.com is an alias for www.l.google.com.
www.l.google.com has address 74.125.39.147
www.l.google.com has address 74.125.39.103
www.l.google.com has address 74.125.39.99
www.l.google.com has address 74.125.39.106
www.l.google.com has address 74.125.39.104
www.l.google.com has address 74.125.39.105

I did not find any example where a hostname resolves to an alias that does not resolve to an ip address, but I think the case might occur.

More than multiples ip addresses and aliases, is there some other special cases... what about ipv6 ? You could try:

$ host ipv6.google.com
ipv6.google.com is an alias for ipv6.l.google.com.
ipv6.l.google.com has IPv6 address 2a00:1450:8007::68

Where the hostname ipv6.google.com is an ipv6 only hostname. What about dual stack hostnames:

$ host www.facebook.com
www.facebook.com has address 66.220.153.15
www.facebook.com has IPv6 address 2620:0:1c08:4000:face:b00c::

Again about ipv6, if your host is ipv4 only, you can still resolve ipv6 addresses (tested on a ipv4 only WinXP and with ipv6.google.com, you could try it on Linux). In this case, the resolution succeeds, but a ping fails with an unknown host error message. This might be a case where your scripting fails.

I hope those remarks were usefull.

share|improve this answer
    
What a great complement to the accepted answer, showing all the edge cases that one might want to deal with in scripting. My version host does not even state "has address" for my boxes. –  Mihai Danila Feb 15 '13 at 23:23

To avoid the problem with aliases and always get a single IP address ready for use:

python -c 'import socket; print socket.gethostbyname("www.example.com")'
share|improve this answer
getent hosts unix.stackexchange.com | cut -d' ' -f1
share|improve this answer
ping -q -c 1 -t 1 your_host_here | grep PING | sed -e "s/).*//" | sed -e "s/.*(//"

works without dependencies on other systems (and for hosts specified in /etc/hosts)

share|improve this answer
1  
The use of ping is what I needed as I need the value from the hosts file but the sed pattern parsing correctly but this worked ping -q -c 1 -t 1 your_host_here | grep PING | sed -e "s/^[^(]*[(]//" | sed -e "s/[)].*$//" –  ManiacZX Jan 18 '13 at 19:23

You could use host:

hostname=example.org

# strips the IP
IP=$( host ${hostname} | sed -e "s/.*\ //" )

# checks for errors
if [ $? -ne 0 ] ; then
   echo "Error: cannot resolve ${hostname}" 1>&2
   exit 1;
fi
share|improve this answer
    
I'm not sure, but my host does return an error code (1) for unknown domains, and it says: "Host asdf not found: 3(NXDOMAIN)". –  phunehehe Sep 15 '11 at 15:10
    
Indeed it does, sorry. I'll update –  Matteo Sep 15 '11 at 15:38
2  
$HOSTNAME should be $hostname -- by convention, we capitalize environment variables (PAGER, EDITOR, SHELL, ...) and internal shell variables (BASH_VERSION, RANDOM, ...). All other variable names should contain at least one lowercase letter. This convention avoids accidentally overriding environmental and internal variables. –  Chris Down Sep 15 '11 at 16:23
    
@Chris: thanks, edited –  Matteo Sep 15 '11 at 17:46

Here is a slight variation of the ping approach that takes "unknown host" into account (by piping through stderr) and uses tr to avoid the use of sed regexps:

ping -c1 -t1 -W0 www.example.com 2>&1 | tr -d '():' | awk '/^PING/{print $3}'

In case it's important to capture the exit value, then the following will work (although less elegant):

ping -c1 -t1 -W0 www.example.com &>/dev/null && ping -c1 -t1 -W0 www.example.com 2>&1 | tr -d '():' | awk '/^PING/{print $3}'
share|improve this answer

Simple but usefull:

  1. getent ahostsv4 www.google.de | grep STREAM | head -n 1 | cut -d ' ' -f 1
  2. getent ahostsv6 www.google.de | grep STREAM | head -n 1 | cut -d ' ' -f 1
  3. getent hosts google.de | head -n 1 | cut -d ' ' -f 1

All commands will resolve an IP address if host still exist. If host points to CNAME it will also get the IP in that case.

The first command returns the resolved IPv4 address

The second command returns the resolved IPv6 address

The third command will return the owners preferred address what may IPv4 or IPv6 address.

share|improve this answer

here's a Bash recipe I cooked up using other folk's answers — first tries /etc/hosts, then falls back to nslookup:

resolveip(){
    local host="$1"
    if [ -z "$host" ]
    then
        return 1
    else
        local ip=$( getent hosts "$host" | awk '{print $1}' )
        if [ -z "$ip" ] 
        then
            ip=$( dig +short "$host" )
            if [ -z "$ip" ]
            then
                echo "unable to resolve '$host'" >&2 
                return 1
            else
                echo "$ip"
                return 0
            fi
        else
            echo "$ip"
            return 0
        fi
    fi
}
share|improve this answer
    
To be clear, getent hosts isn't just a lookup in /etc/hosts - it's a full-on DNS-resolving call to gethostbyaddr(3), and it's very unlikely to fail in a case where dig will succeed. See the man page for getent. –  Stuart P. Bentley Aug 3 at 11:42
    
@Stuart is right — i've learned a great deal since writing that and oversimplified a powerful command. getent remains my favorite, although i also like dig +short –  RubyTuesdayDONO Aug 3 at 18:26

To complete Chris Down's answer, and address jfgagne comments about (possibly chained) aliases, here is a solution that :

  • takes into account multiple IPs
  • takes into account one or more aliases (CNAME)
  • does not query /etc/hosts file (in my case I didn't want it); to query it, dbernt's python solution is perfect)
  • does not use awk/sed

    dig +short www.alias.com  | grep -v "\.$" | head -n 1
    

Always returns the first IP address, or empty tring if not resolved. with version of dig :

    $ dig -v
    DiG 9.8.1-P1
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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