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

评论

令人遗憾的是,getent 答案位于底部附近的某个地方。它是最简单的,不需要额外的程序包,并且也更易于从Bash脚本进行解析。

@ 0xC0000022L:新的可耻之处是该答案建议将getent主机托管在somehost上,而在somehost上运行该主机时,将生成一个IPv6地址,这与大多数其他工具(至少ping,ssh)解析名称并破坏某些内容的方式不同。使用ahosts代替主机。

@j_random_hacker:谁阻止您请求IPv4(ahostsv4)或IPv6(ahostsv6)地址?我个人认为返回IPv6的非特定请求没有问题。您的代码应该准备好了。 IPv6已经存在了20多年了。

@ 0xC0000022L:没有人“吓我一跳”,但是答案明确地暗示了主机,到目前为止,有4个人赞成vinc17的评论,表达了由“突然的IP​​v6”引起的痛苦。为IPv6做好准备并不总是问题:许多程序需要一种方法来确定两个名称/地址是否引用同一主机。他们可以使用简单的字符串匹配,或者必须对网络了解很多,才能找到“真实”的答案。后者是一个雷区,许多第三方程序和系统-我无法控制-使用前者。

#1 楼

您可以使用getent随附的glibc(因此几乎可以肯定在Linux上具有它)。这可以通过使用gethostbyaddr / gethostbyname2来解决,因此也将检查/etc/hosts / NIS / etc: (直接查询DNS服务器,而不查看dig / NSS / etc):

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


如果+short不可用,则以下任何一项都可以工作。所有这些都直接查询DNS,而忽略其他解决方法:如果只打印一个IP,则将/etc/hosts命令添加到dig +short的工作流程中。

dig +short unix.stackexchange.com


评论


默认情况下,使用dig仅适用于ipv4,其中主机同时给出ipv4和ipv6答案。这可能是意外的。您可以尝试托管www.google.com,dig + short www.google.com,托管ipv6.google.com,dig + short ipv6.google.com,托管www.facebook.com,dig + short www.facebook.com 。

– jfg956
2011年9月21日15:21

DIG不起作用,如果是CNAME,则不会返回IP。

–索林
2014年3月14日14:23在

有时,主机可能会超时并且什么也不返回。对于某些域,dig + short可能会在第一行中返回域别名。因此,要确保输出是IPv4地址,请使用dig + short example.com | grep -Eo'[0-9 \。] {7,15}'|头-1。

–caiguanhao
2014年6月7日15:25

使用getent主机是不正确的,例如,当IPv6不起作用时,它可能会提供一个IPv6地址。正确的解决方案是在需要时使用getent ahosts 尝试同时使用IPv6和IPv4。

–vinc17
16-10-3在15:02

值得一提的是:host,dig和nslookup似乎直接与resolv.conf中列出的服务器通信,而“ getent主机”(如果启用)同时尊重本地主机文件和库级缓存(例如nscd)。

–芥末酱
17年6月12日在11:59

#2 楼

使用来自dnsutils软件包的host

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


(根据注释正确的软件包名称。请注意,其他发行版在不同的软件包中也包含host:Debian / Ubuntu bind9-host ,openSUSE bind-utils,Frugalware绑定。)

评论


如果您需要解析DNS中不存在的内容(例如/ etc / hosts),请参见下面的resolveip条目

–加文·布罗克(Gavin Brock)
2012年7月2日在8:56

请注意,主机有时会返回多行输出(在重定向的情况下),您将需要主机unix.stackexchange.com |如果只希望带有IP地址的行,则为tail -n1。

–爱德华·科菲
13年1月23日在5:04

有多个具有不同输出格式的“主机”版本。例如。大多数系统似乎都具有BIND9版本,但是我的Ubuntu 10.04 LTS服务器具有某些完全不同的版本。

– ColinM
2014年5月22日19:51

如果您没有安装主机或dig,则可以使用ping来代替它,它始终可用:ping unix.stackexchange.com -c 1 -q 2>&1 | grep -Po“(\ d {1,3} \。){3} \ d {1,3}”这不需要在大多数Unix / Linux matchines上安装任何额外的软件包。

– Boynux
14年5月23日在8:18



这个答案值得认真的否决。 host是一个DNS工具(类似于nslookup),因此它仅在DNS中查找主机,而不在例如DNS中查找主机。 / etc / hosts。因此,这不是对OP问题的答案。

– peterh
2014年9月11日上午9:49

#3 楼

我的机器上有一个似乎可以完成此工作的工具。手册页显示它似乎是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


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

评论


这似乎是这里唯一使用操作系统的内置解析程序的解决方案-因此适用于/ etc / hosts和DNS。

–加文·布罗克(Gavin Brock)
2012年7月2日在8:57



如另一个答案中所述,getent也查看/ etc / hosts,并且带有glibc,因此与Linux系统无关。

–阿斯范·卡兹
16年4月16日在13:32

我不会使用resolveip,因为您在另一个程序包上创建了依赖项。默认情况下安装getent。 host,nslookup和dig都在可选软件包中。绝对在脚本中使用getent。

–迈克尔·格兰特(Michael Grant)
4月21日17:07

我喜欢这个答案,但它不返回ipv6

– MaXi32
7月11日8:36

#4 楼

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

$ 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),将全部返回。到目前为止,此“问题”影响到此问题中提到的所有工具:

评论


请注意,如果域具有CNAME条目,则其域可能会打印在第一行而不是IP地址。

– pcworld
18年4月27日在23:27

#5 楼

getent hosts unix.stackexchange.com | cut -d' ' -f1


评论


还要考虑使用getent的ahosts,ahostsv4,ahostsv6。

– 0xC0000022L
15年4月29日在22:12

cut不会用于getent,而使用\ t分隔列。在Solaris上就是这种情况。

–天花板
16年3月18日在9:51

@ceving:在Solaris上,您可能必须运行不带-d的cut(默认为\ t作为定界符)。在Linux上,它是空格,因此上面的行适用。

– Borssky
16年4月7日在22:24

#6 楼

到目前为止,给出的解决方案大多在较简单的情况下起作用:主机名直接解析为单个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失败,并显示未知的主机错误消息。这可能是您的脚本编写失败的情况。

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

评论


这是对已接受答案的一个很好的补充,它显示了在脚本编写中可能要处理的所有极端情况。我的版本主持人甚至没有为我的盒子声明“有地址”。

– Mihai Danila
13年2月15日在23:23

#7 楼

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

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


评论


我通过以下答案制作了一个bash函数以粘贴到我的bashrc中:gist.github.com/brycepg/ba117a37de53906dc8fcc312bd7d5fee

–布莱斯·昆塔
17年8月11日在16:58



python3 -c'导入套接字;打印(socket.gethostbyname(“ www.example.com”))'

– FelikZ
19年11月21日在12:35

#8 楼

ping -q -c 1 -t 1 your_host_here | grep PING | sed -e "s/).*//" | sed -e "s/.*(//"


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

评论


使用ping是我需要的,因为我需要从hosts文件中获取值,但sed模式可以正确解析,但是可以使用ping -q -c 1 -t 1 your_host_here | grep Ping | sed -e“ s / ^ [^(] * [(] //” | sed -e“ s /[)].*$//”

–ManiacZX
2013年1月18日19:23



要解决我的家庭网络上的某些问题(例如myhostname.local),此方法有效,因此对我来说,这是最佳答案。

–马特·弗里德曼
15年1月24日在2:59

我也可以建议:ping -q -c 1 -t 1 bahface.local | grep -m 1 PING |剪切-d“(” -f2 |剪切-d“)” -f1

–马特·弗里德曼
15年1月24日,3:08

getent 也适用于/ etc / hosts内的声明……它是各种系统数据库(passwd,group,别名,服务)的首选工具。

– 0xC0000022L
15年4月30日在7:53

#9 楼

简单但有用:

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

如果主机仍然存在,则所有命令都将解析IP地址。如果主机指向CNAME,则在这种情况下也将获得IP。
第一个命令返回解析的IPv4地址。
第二个命令返回解析的IPv6地址。
第三个命令将返回所有者的首选地址,该地址可以是IPv4或IPv6地址。

评论


到目前为止,最简单的一种。并且默认情况下可用。不像需要安装bindutils的主机

– Michaelbn
2015年10月21日在6:45



#10 楼

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

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


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

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


评论


我喜欢这个解决方案,因为它不需要任何额外的工具即可工作。

– Radon8472
18年8月9日在8:14

#11 楼

为了完成Chris Down的回答并解决jfgagne关于(可能是链接的)别名的评论,这里提供了一种解决方案:别名(CNAME)
不查询/etc/hosts文件(就我而言,我不想要它);要查询它,dbernt的python解决方案是完美的)

不使用awk / sed

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



总是返回第一个IP地址,如果未解决,则为空tring。带有dig版本:

    $ dig -v
    DiG 9.8.1-P1


评论


谢谢,其他答案都假定“ dig + short”总是返回一个IP地址。他们没有考虑CNAME。

–贾姆希德
16年5月10日,0:46

#12 楼

 php -r "echo gethostbyname('unix.stackexchange.com');"


评论


这可行,但需要在终端上安装php

– Radon8472
18年8月9日在8:29

在“主机”,“挖掘”等不可用的典型php docker容器上非常有用

–法比安·施蒙格勒(Fabian Schmengler)
18/09/5在19:42

#13 楼

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

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

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


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

#14 楼

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


#15 楼

这是我使用其他人的答案烹制的Bash食谱-首先尝试/etc/hosts,然后退回到nslookup:

 resolveip(){
    local host=""
    if [ -z "$host" ]
    then
        return 1
    else
        local ip=$( getent hosts "$host" | awk '{print }' )
        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
}
 


评论


需要明确的是,getent主机不仅仅是在/ etc / hosts中进行查找-它是对gethostbyaddr(3)的完整DNS解析调用,在挖掘成功的情况下,失败的可能性很小。请参阅手册页以获取getent。

– Stuart P. Bentley
14年8月3日,11:42

@Stuart是正确的-自编写该书以来,我学到了很多东西,并且简化了一个强大的命令。尽管我也喜欢dig + short,但getent仍然是我的最爱

– RubyTuesdayDONO
2014年8月3日在18:26

#16 楼

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


是我在没有DNS服务器的情况下找到的解决方案

#17 楼

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

# $(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 "" 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

#18 楼

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

评论


在某种程度上,答案会比现有的答案有所改善。另外,请将命令缩进4个空格(请参阅markdown语法)。

–maxschlepzig
16 Mar 17 '16 at 21:14

#19 楼

挖得太慢,nslookup快得多

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


#20 楼

1行解析主机名列表

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


#21 楼

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

因此,我为dns.lookup编写了一个愚蠢的包装,供您安装Node.js来提供CLI的您使用:

评论


在您下定决心之前,有60%的断裂几率。

– dotbit
19年8月27日在11:58

@dotbit您能详细说明吗?自从17年以来,我每周都在使用此书,从来没有任何问题。

–托马斯·詹森(Thomas Jensen)
19年8月27日在20:47

@Jensen,但您像往常一样是唯一的一个。我们其余的人通常都会遇到一种或另一种失败,并且总是失败。

– dotbit
19年8月30日在5:55

“一如既往”是什么意思? “我们其余的人”是谁? “遇到失败”您看到什么具体问题?我很好奇。

–托马斯·詹森(Thomas Jensen)
19年8月31日在13:59



#22 楼

我不知道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


评论


使用ping很好,因为每个人都有它,但是,如果您想在脚本中使用它,则需要从输出中过滤IP部件。

– Radon8472
18年8月9日在8:27

#23 楼

是的,已经有了很多答案,但是缺少使用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进行安装。

评论


perl -MSocket -MNet :: hostent -E'say inet_ntoa((gethost shift)-> addr)'unix.stackexchange.com 2> / dev / null更干净了。但是除了我们两个人之外,其他人都没有使用pörl,其他所有人当然都使用了Pascal Script。

– dotbit
19年8月27日在12:02



实际上,如果发生任何问题,我更喜欢查看错误消息。无法在未定义的值上调用方法“ addr”并不是最好的错误消息,但可能会提示问题。

–Slaaven Rezic
19年8月30日在11:21

#24 楼

#!/bin/bash

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

resolveip -s      RT.com
dig       +short  RT.com
host              RT.com | awk '/has address/ { print  }'
nslookup          RT.com | awk '/^Address: /  { print  }'
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!  "


评论


红宝石版本在IP地址周围打印引号---可能应该使用打印代替p。

–Slaaven Rezic
19年8月30日在11:26



thx,@ Slaven Rezic,随时可以投票。再一次,在底部的脚本实际上可能更可见... ;-)

– dotbit
19年8月30日在17:47



#25 楼

host -t a cisco.com


此命令将显示ip地址(将域名转换为IP)

#26 楼

除了上述解决方案之外,您还可以通过以下脚本将多个主机名转换为ip,唯一的依赖项是核心Unix中的“ ping”命令:

getip(){ ping -c 1 -t 1  | head -1 | cut -d ' ' -f 3 | tr -d '()' 2>&1 | tee >> /tmp/result.log & }

getip 'hostname.number1.net'

getip 'hostname.number2.net'

getip 'hostname.number3.net'

getip 'hostname.number4.net'

getip 'hostname.number5.net'

getip 'hostname.number6.net'

getip 'hostname.number7.net'

getip 'hostname.number8.net'


$ cat /tmp/result.log

ABC.DEF.GHI.XY1

ABC.DEF.GHI.XY2

ABC.DEF.GHI.XY3

ABC.DEF.GHI.XY4

ABC.DEF.GHI.XY5

ABC.DEF.GHI.XY6

ABC.DEF.GHI.XY7

ABC.DEF.GHI.XY8