58

There are several command line utilities to resolve host names (host, dig, nslookup), however they all use nameservers exclusively, while applications in general look in /etc/hosts first (using gethostbyname I believe).

Is there a command line utility to resolve host names that behaves like a usual application, thus looking in /etc/hosts first and only then asking a nameserver?

(I am aware that it would probably be like 3 lines of c, but I need it inside of a somewhat portable shell script.)

2
  • Could you please explain your situation a little more? Does awk '/hostname/ { print $1 }' /etc/hosts help?
    – quanta
    Aug 22, 2011 at 11:08
  • @quanta Actually the current solution is grep/sed magic on /etc/hosts. I wanted to make that more general with a fallback.
    – Zulan
    Aug 22, 2011 at 11:20

12 Answers 12

81

This is easily achieved with getent:

getent hosts 127.0.0.1

getent will do lookups for any type of data configured in nsswitch.conf.

2
33

One tool that would work is getent. So you could use getent hosts www.google.com, or getent hosts localhost. It will retrieve entries from the databases as specified in your Name Service Switch configuration /etc/nsswitch.conf.

For more modern implementations use getent ahosts www.google.com which will get multiple results.

6
  • 1
    Yes, but that would not fall back on DNS.
    – slowpoison
    Mar 19, 2012 at 19:55
  • No, it resolves it in nsswitch.conf order.
    – cjc
    Mar 19, 2012 at 19:58
  • @slowpoison, Take a look at your nsswitch config. My system has files dns for hosts, which means /etc/hosts is consulted and then the DNS resolver. Your config may be different.
    – Zoredache
    Mar 19, 2012 at 20:07
  • @cjc, it does. I don't think I tried it correctly.
    – slowpoison
    Mar 19, 2012 at 20:07
  • @Zoredache, I'm quite impressed with getent. Thanks for the intro to this command.
    – slowpoison
    Mar 19, 2012 at 20:11
12

Use getent ahosts, for instance:

$ getent ahosts www.google.com | sed -n 's/ *STREAM.*//p'
216.58.210.196
2a00:1450:4006:803::2004

You'll get all IPv4 and IPv6 addresses, via the glibc resolver (thus using /etc/hosts first, as usually configured in /etc/nsswitch.conf).

Do not use getent hosts, as it will give you either IPv6 or IPv4 addresses (not both), and the chosen protocol may not be one that does not work. Indeed, IPv6 addresses are generally preferred, but at some places, IPv6 data are filtered (not supported) by the routers.

2
  • This is the correct answer. Apr 17, 2020 at 18:59
  • This indeed is the correct answer for me because You'll get all IPv4 and IPv6 addresses.
    – Alex
    Jul 26, 2022 at 20:59
10

You can use a gethostbyname() (deprecated) wrapper like:

python -c 'import socket;print socket.gethostbyname("www.google.com")'

Or a getaddrinfo() wrapper like:

python -c 'import socket;print socket.getaddrinfo("www.google.com","http")[0][4][0]'

For python3:

python -c 'import socket;print(socket.getaddrinfo("www.google.com","http")[0][4][0])'

Note that getaddrinfo will return all instances as a list. The last part of the command selects only the first tuple. This can also return IPv6 addresses.

4
7

resolveip will do this.

Oddly, it's part of the mysql-server packages on RHEL and Ubuntu.

7

You could use [your favorite language here] to write a script that calls getnameinfo. That is how binaries (like ping) should be doing it, so you're ensured you get the same treatment.

6

You could be really hacky and use arp:

arp -n somehostname | tr -d '()' | awk '{print $2}'

but that would be really ugly so you shouldn't do that.

4

"gethostbyname" command line version:

#!/usr/bin/perl
use Socket;

$host = shift @ARGV;
die("usage: gethostbyname hostname\n") unless(defined($host));

$packed_ip = gethostbyname($host);

if (defined $packed_ip) {
    $ip_address = inet_ntoa($packed_ip);
    print "$ip_address\n";
    exit 0
} else {
    warn "$host not found\n";
    exit 1
}
2

Try this:

if [ `grep -c "hostname" /etc/hosts` -ge 1 ]; then
    ip=`awk '/hostname/ { print $1 }' /etc/hosts`
else
    ip=`host hostname | awk '/hostname has address/ { print $4 }'`
fi
2

getent hosts is broken. It prefers IPv6 addresses, gai.conf should be configured to prefer ipv4 but....

The Perl gethostbyname uses the precedence in /etc/nsswitch.conf

hosts: files dns

So this works like getent hosts should work for me.

Also:

perl -e 'use Socket; print inet_ntoa(inet_aton("www.google.com")) . "\n";'

should work.

1
  • 7
    It's not broken, it just doesn't use getaddrinfo (which reads /etc/gai.conf). To use getaddrinfo, run getent ahosts.
    – craig65535
    Oct 12, 2015 at 18:35
0

If you are on a Debian-based distro:

sudo apt-get update
sudo apt-get install libsocket-getaddrinfo-perl
socket_getaddrinfo one.one.one.one

# Resolved host 'one.one.one.one', service '0'
# 
# socket(AF_INET , SOCK_STREAM, IPPROTO_TCP) + '1.1.1.1:0'
# socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP) + '1.1.1.1:0'
# socket(AF_INET , SOCK_RAW   , IPPROTO_IP ) + '1.1.1.1:0'
# socket(AF_INET , SOCK_STREAM, IPPROTO_TCP) + '1.0.0.1:0'
# socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP) + '1.0.0.1:0'
# socket(AF_INET , SOCK_RAW   , IPPROTO_IP ) + '1.0.0.1:0'
# socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) + '[2606:4700:4700::1111]:0'
# socket(AF_INET6, SOCK_DGRAM , IPPROTO_UDP) + '[2606:4700:4700::1111]:0'
# socket(AF_INET6, SOCK_RAW   , IPPROTO_IP ) + '[2606:4700:4700::1111]:0'
# socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) + '[2606:4700:4700::1001]:0'
# socket(AF_INET6, SOCK_DGRAM , IPPROTO_UDP) + '[2606:4700:4700::1001]:0'
# socket(AF_INET6, SOCK_RAW   , IPPROTO_IP ) + '[2606:4700:4700::1001]:0'

socket_getaddrinfo localhost

# Resolved host 'localhost', service '0'
# 
# socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) + '[::1]:0'
# socket(AF_INET6, SOCK_DGRAM , IPPROTO_UDP) + '[::1]:0'
# socket(AF_INET6, SOCK_RAW   , IPPROTO_IP ) + '[::1]:0'
# socket(AF_INET , SOCK_STREAM, IPPROTO_TCP) + '127.0.0.1:0'
# socket(AF_INET , SOCK_DGRAM , IPPROTO_UDP) + '127.0.0.1:0'
# socket(AF_INET , SOCK_RAW   , IPPROTO_IP ) + '127.0.0.1:0'
-1

The following command will perform lookup via DNS /etc/hosts over direct DNS server lookup.

ping -W2 -c1 google.com | grep PING | sed -r "s/^[^\(]*\(([\.0-9]*)\).*/\1/"

This command will attempt to ping a domain (in this case, google.com) once with a wait timeout of 2 seconds, get the first line of the PING command which will state "PING google.com (216.58.199.36) 56(84) bytes of data", then use Stream Editor (sed) to detect the first set of brackets and extract the data within it which is the IP address we are looking for.

NOTE: the regex expression will not work if there are parenthesis (aka circular brackets) in the URL, but this would be a rare case.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .