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
@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.
27 Answers 27
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 unix.stackexchange.com | 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 unix.stackexchange.com
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 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 >' getent hosts unix.stackexchange.com | awk '< print $1 ; 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 >'
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 .
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 example.com | grep -Eo ‘[0-9\.]<7,15>‘ | head -1 .7,15>
Using getent hosts
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.
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 in different packages: Debian/Ubuntu bind9-host, openSUSE bind-utils, Frugalware bind.)
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.
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..
if you don’t have host or dig installed you can use ping instead which is always available: ping unix.stackexchange.com -c 1 -q 2>&1 | grep -Po «(\d<1,3>\.)\d<1,3>» this does not need any extra packages install on most Unix/Linux matchines.1,3>
This answer deserves a serious downvote. host is a DNS tool (similar to nslookup ) so it only looks up hosts in DNS, not in e.g. /etc/hosts . So it is NOT an answer to OP’s question.
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.
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.
getent , as detailed in the other answer, also looks at /etc/hosts, and comes with glibc, so has no dependencies on a Linux system.
I would not use resolveip since you create a dependency on another package. getent is installed by default. host, nslookup, and dig are all in optional packages. Definitely use getent in a script.
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:
Note that if a domain has a CNAME entry its domain may be printed in the first line instead of an IP address.
getent hosts unix.stackexchange.com | cut -d' ' -f1
@ceving: On Solaris you might have to run cut without -d (defaults to \t as delimiter ). On Linux it’s spaces, thus the line above works.
The solutions given so far mostly work in the simpler case: the hostname directly resolves to a single IPv4 address. This might be the only case where you need to resolve hostnames, but if not, below is a discussion on some cases that you might need to handle.
Chris Down and Heinzi briefly discussed the case where the hostname resolves to more than one IP addresses. In this case (and others below), basic scripting under the assumption that a hostname directly resolves to a single IP address may break. Below, 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 needs to be introduced. Let’s check the example below:
$ 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 multiple 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 below:
$ 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 multiple 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 useful.
Finding an IP address from an interface name
On a Linux box, the common interface names look like eth0, eth1, etc. I know how to find at least one IP address using gethostbyname or similar functions, but I don’t know any way to specify which named interface I want the IP address of. I could use ifconfig and parse the output, but shelling out for this information seems. inelegant. Is there a way to, say, enumerate all the interfaces and their IP addresses (and maybe MAC addresses) into a collection? Or at least something along the lines of gethostbyinterface(«eth0») ?
2 Answers 2
// Originally from http://www.tlug.org.za/wiki/index.php/Obtaining_your_own_IP_address #include #include #include #include #include #include #include #include #include /** * getIPv4() * * This function takes a network identifier such as "eth0" or "eth0:0" and * a pointer to a buffer of at least 16 bytes and then stores the IP of that * device gets stored in that buffer. * * it return 0 on success or -1 on failure. * * Author: Jaco Kroon */ int getIPv4(const char * dev, char * ipv4) < struct ifreq ifc; int res; int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd < 0) return -1; strcpy(ifc.ifr_name, dev); res = ioctl(sockfd, SIOCGIFADDR, &ifc); close(sockfd); if(res < 0) return -1; strcpy(ipv4, inet_ntoa(((struct sockaddr_in*)&ifc.ifr_addr)->sin_addr)); return 0; > int main()
Update: Moved dead link to a comment (for posterity) (thanks @obayhan), and added syntax highlighting.
edit: I saw you don’t like shelling. Then you can look at how ifconfig does its job (it extracts at least some information from /proc).
When you have interface name, you can do this (in your shell):
ifconfig eth0 | grep 'inet addr' | sed -e 's/:/ /' | awk ''
To enumerate interfaces you can use this:
for x in `ifconfig | egrep '^[^ ]' | awk ''`; do echo -n "$" echo -n " " ifconfig "$" | grep 'inet addr' | sed -e 's/:/ /' | awk '' done