it-swarm.cn

如何在Bash脚本中将主机名解析为IP地址?

在Bash脚本中将主机名解析为IP地址的最简洁方法是什么?我正在使用 Arch Linux

450
Eugene Yarmash

您可以使用getent随附的glibc(因此几乎可以肯定在Linux上具有它)。使用gethostbyaddr/gethostbyname2可以解决此问题,因此也会检查/etc/hosts/NIS/etc:

getent hosts unix.stackexchange.com | awk '{ print $1 }'

或者,就像海因兹在下面说的那样,您可以将Dig+short参数(直接查询DNS服务器,不查看/etc/hosts/NSS/etc):

Dig +short unix.stackexchange.com

如果Dig +short不可用,以下任何一项都可以工作。所有这些都直接查询DNS,而忽略其他解决方法:

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 }'

如果只想打印一个IP,则将exit命令添加到awk的工作流程中。

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 }'
570
Chris Down

使用 dnsutils 包中的Host

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

根据注释更正的软件包名称。注意,其他发行版在不同的软件包中有Host:Debian/Ubuntubind9-Host,openSUSEbind-utils,Frugalwarebind。)

146
manatwork

我的机器上有一个可以完成这项工作的工具。手册页显示它似乎与mysql一起提供...这是使用它的方法:

resolveip -s unix.stackexchange.com
64.34.119.12

如果无法解析主机名,则此工具的返回值不同于0:

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

[〜#〜] update [〜#〜]在Fedora上,它带有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

我想这会为您的脚本创建一个奇怪的依赖关系...

56
greg0ire

以下使用Dig的命令允许您直接读取结果,而无需任何sed/awk/etc。魔法:

$ Dig +short unix.stackexchange.com
64.34.119.12

Dig包中也包含dnsutils


Dig的返回值为0,即使无法解析该名称也是如此。因此,您需要检查输出是否为空,而不是检查返回值:

hostname=unix.stackexchange.com

ip=`Dig +short $hostname`

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

注2:如果主机名具有多个IP地址(例如,尝试debian.org),则将全部返回。到目前为止,此“问题”影响到此问题中提到的所有工具:

45
Heinzi
getent hosts unix.stackexchange.com | cut -d' ' -f1
44
sborsky

到目前为止,给出的解决方案大多在较简单的情况下起作用:主机名直接解析为单个IPv4地址。这可能是唯一需要解析主机名的情况,但是如果不需要,下面是有关可能需要处理的某些情况的讨论。

Chris Down和Heinzi简要讨论了主机名解析为多个IP地址的情况。在这种情况下(以及下面的其他情况),假定主机名直接解析为单个IP地址的基本脚本可能会中断。下面是一个主机名解析为多个IP地址的示例:

$ 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

但是www.l.google.com是什么?这是需要引入别名的情况。让我们检查以下示例:

$ 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

因此,www.google.com不能直接解析为IP地址,而可以解析为别名本身可以解析为多个IP地址。有关别名的更多信息,请检查 此处 。当然,别名具有单个IP地址的情况是可能的,如下所示:

$ 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

但是别名可以链接吗?答案是肯定的:

$ 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

我没有找到主机名解析为别名而不解析为IP地址的任何示例,但我认为可能会发生这种情况。

除了多个IP地址和别名外,还有其他一些特殊情况... IPv6呢?您可以尝试:

$ 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

其中主机名ipv6.google.com是仅IPv6的主机名。那么双栈主机名呢:

$ 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::

再次关于IPv6,如果您的主机仅是IPv4,您仍然可以解析IPv6地址(在仅IPv4的WinXP上进行测试,并使用ipv6.google.com,可以在Linux上进行尝试)。在这种情况下,解析成功,但是ping失败,并显示未知主机错误消息。这可能是脚本编写失败的情况。

我希望这些评论是有用的。

30
jfg956

为避免别名出现问题,并始终准备使用一个IP地址:

python -c 'import socket; print socket.gethostbyname("www.example.com")'
22
dbernt

简单但有用:

  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

如果主机仍然存在,则所有命令都将解析IP地址。如果主机指向CNAME,则在这种情况下也将获得IP。

第一条命令返回解析的IPv4地址

第二条命令返回解析的IPv6地址

第三个命令将返回所有者的首选地址,可以是IPv4或IPv6地址。

19
Tom Freudenberg
ping -q -c 1 -t 1 your_Host_here | grep PING | sed -e "s/).*//" | sed -e "s/.*(//"

可以不依赖于其他系统(和/ etc/hosts中指定的主机)使用

19
Andrew McGregor

这是ping方法的细微变化,它考虑了“未知主机”(通过stderr进行管道传输),并使用tr来避免使用sed正则表达式:

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

如果捕获出口值很重要,则可以使用以下方法(尽管不太优雅):

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

为了完成Chris Down的答案,并解决jfgagne关于(可能是链接的)别名的评论,以下是一种解决方案:

  • 考虑到多个IP
  • 考虑一个或多个别名(CNAME)
  • 不查询/etc/hosts文件(在我的情况下,我不想要它);查询它,dbernt的python完美的解决方案)
  • 不使用awk/sed

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

始终返回第一个IP地址,如果未解析则返回空值。使用Dig版本:

    $ Dig -v
    Dig 9.8.1-P1
8
Franck
 php -r "echo gethostbyname('unix.stackexchange.com');"
6
Mohammed Zourob

我希望将此添加为对Andrew McGregor Re:ping的评论。但是,它不允许我这样做,因此我需要将其添加为另一个答案。 (如果有人可以将其添加为评论,请随意。)

这是另一个变体,仅使用ping和grep:

ping -q -c1 -t1 your_Host_here | grep -Eo "([0-9]+\.?){4}"

grep -E表示扩展的正则表达式,而grep -o仅返回匹配的部分。正则表达式本身会查找一个或多个数字([0-9]+)和一个点(\.?) 四次 ({4}

6
Dweia
nmap -sP 192.168.178.0/24|grep YOUR_HOSTNAME|sed -n 's/.*[(]\([0-9\.]*\)[)].*/\1/p'

是我发现没有DNS服务器的解决方案

5
Philippe Gachoud

这是我使用其他人的答案制作的Bash食谱-首先尝试/etc/hosts,然后退回到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
}
5
RubyTuesdayDONO

您可以使用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
5
Matteo

也许不是最简洁,但是它似乎是健壮和高效的:

# $(get_Host_dns_short "google.com")
#
# Outputs the IPv4 IP Address of a hostname, resolved by DNS. Returns 0 if DNS
# responded successfully; 1 otherwise. Will mask error output.
function get_Host_dns_short()
{
    (
        set -o pipefail

        Host -4 -W1 -t A "$1" 2>/dev/null | awk '/has address/ { print $NF; exit }'
    ) && return 0 || return 1
}

这将输出一个IPv4 IP,并返回1如果发生故障,则屏蔽stderr输出。

您可以像这样使用它:

GOOGLE_IP="$(get_Host_dns_short "google.com")"
if [[ $? -eq 0 ]]; then
    echo "Google's IP is ${GOOGLE_IP}."
else
    echo "Failed to resolve Google's IP."
fi

Google的IP是216.58.192.46。

如果您想使用IPv6地址,只需替换-4-6

4
Will

Dig太慢,nslookup快得多

nslookup google.com | grep -Po 'Address:\s*[0-9.]+' | tail -1 | sed -e 's/Address:\s*//g'
4
Andrey Izman

Dig +noall +answer +nocomments example.com | awk '{printf "%-36s\t%s\n", $1, $5 }'

4
D P Baker

1行解析主机名列表

for LINE in `cat ~/Desktop/mylist`; do a=$(nslookup $LINE | awk '/^Address: / { print $1 }');  echo $a >> ~/Desktop/ip; done
3
Andy Wong

我不知道bash脚本的最简单方法,但是如果您要解析主机名并查看主机是否启动,请使用ping

ping -a hostname -c 1

ping主机一次并将主机名解析为IP地址。

$ ping -a www.google.com -c 1
PING www.google.com (216.58.211.132) 56(84) bytes of data.
64 bytes from arn09s10-in-f4.1e100.net (216.58.211.132): icmp_seq=1 ttl=54 time=1.51 ms
3
user257655

我一直在没有getent的Mac上执行此操作。 ping似乎很hack。我也想考虑/etc/hosts

因此,我为安装了Node.js的CLI的dns.lookup写了一个愚蠢的包装:

$ npm install -g lookup-hostname
$ lookup google.com
62.243.192.89
3
Thomas Jensen
#!/bin/bash

systemd-resolve   RT.com -t A  | awk '{ print $4 ; exit }'
systemd-resolve unix.stackexchange.com -t A --legend=no | awk '{ print $4 ; exit }'

resolveip -s      RT.com
Dig       +short  RT.com
Host              RT.com | awk '/has address/ { print $4 }'
nslookup          RT.com | awk '/^Address: /  { print $2 }'
ping -q -c 1 -t 1 RT.com | grep PING | sed -e "s/).*//" | sed -e "s/.*(//"

Ruby     -rresolv -e      ' print    Resolv.getaddress "RT.com" '
python2  -c 'import socket; print socket.gethostbyname("RT.com")'
Perl     -MSocket -MNet::hostent -E 'say inet_ntoa((gethost shift)->addr)' RT.com  2>/dev/null
php      -r "echo gethostbyname( 'RT.com' );"

echo        "   all do work for me - take your pick!  "
2
dotbit

是的,已经有很多答案,但是缺少使用Perl的解决方案:

Perl -MSocket -MNet::hostent -E 'say inet_ntoa((gethost shift)->addr)' unix.stackexchange.com

在bash脚本中,可以这样使用:

#!/bin/bash
ipaddr=$(Perl -MSocket -MNet::hostent -E 'say inet_ntoa((gethost shift)->addr)' unix.stackexchange.com)
echo $ipaddr

这里使用的模块是核心模块,因此应该随处可用,而无需与CPAN一起安装。

2
Slaven Rezic