将主机名解析为 IP 地址的便携式方法

Portable way to resolve host name to IP address

我需要在 shell 脚本中将主机名解析为 IP 地址。代码必须至少在 CygwinUbuntuOpenWrt(busybox) 中有效。 可以假设每一台主机只有一个IP地址。

示例:

编辑: nslookup 可能看起来是一个很好的解决方案,但它的输出非常不可预测且难以过滤。这是我电脑上的结果命令 (Cygwin):

>nslookup google.com
Unauthorized answer:
Serwer:  UnKnown
Address:  fdc9:d7b9:6c62::1

Name:   google.com
Addresses:  2a00:1450:401b:800::200e
          216.58.209.78

我没有使用 OpenWRT 或 Busybox 的经验,但下面的一行代码应该可以与 Cygwin 或 Ubuntu:

的基本安装一起使用
ipaddress=$(LC_ALL=C nslookup $host 2>/dev/null  | sed -nr '/Name/,+1s|Address(es)?: *||p')

以上内容适用于 Ubuntu 和 Windows 版本的 nslookup。但是,它仅在 DNS 服务器回复 one IP(v4 或 v6)地址时有效;如果返回多个地址,将使用第一个地址。


说明

LC_ALL=C nslookup 在 运行 nslookup 命令时设置 LC_ALL 环境变量,以便该命令忽略当前系统区域设置并以命令的默认语言打印其输出(英文).

2>/dev/null 避免了来自 nslookup 的 Windows 版本的关于打印非权威服务器的警告。

sed 命令查找包含 Name 的行,然后在存在多个 IP(v4 或 6)地址时,在删除短语 Addresses: 后打印以下行 -- 或 Address: 当名称服务器只返回一个地址时。

-n 选项表示不打印行,除非有 p 命令while the-r` 选项表示使用扩展的正则表达式(GNU sed 是 Cygwin 的默认设置和 Ubuntu).

如果您想在几乎所有现代 UNIX 上开箱即用,请使用 Python:

pylookup() {
  python -c 'import socket, sys; print socket.gethostbyname(sys.argv[1])' "$@" 2>/dev/null
}

address=$(pylookup google.com)

关于专用工具,dignslookup 更容易使用,并且它的 short 模式仅发出字面答案——在这种情况下,IP地址。只取第一个地址,如果找到多个:

# this is a bash-specific idiom
read -r address < <(dig +short google.com | grep -E '^[0-9.]+$')

如果您需要使用 POSIX sh,或 bash 的损坏版本(例如 Git Bash,使用 mingw 构建,其中进程替换不会' t 工作),那么你可以改为使用:

address=$(dig +short google.com | grep -E '^[0-9.]+$' | head -n 1)

dig 可用于 bind-utils 包中的 cygwin;由于 bind 是 UNIX 上使用最广泛的 DNS 服务器,bind-utils(基于相同的代码库构建)也可用于几乎所有 Unix 系列操作系统。

TL;DR; Option 2 is my preferred choice for IPv4 address. Adjust the regex to get IPv6 and/or awk to get both. There is a slight edit to option 2 suggested use given in EDIT

好吧,这里的回答太晚了,但我想我会在这里分享我的解决方案,尤其是。因为接受的答案在 openWRT 上对我不起作用(没有 python 最小设置)并且 错误 "no address found after comma".

选项 1(给出名称服务器发送的最后一个条目的最后地址):

nslookup example.com 2>/dev/null | tail -2 | tail -1 | awk '{print }'

非常简单直接,不需要解释管道命令。

尽管在我的测试中这总是提供 IPv4 地址(因为 IPv4 总是最后一行,至少在我的测试中是这样。)但是,我读到了 nslookup 的意外行为。所以,我必须找到一种方法来确保即使顺序颠倒了我也能获得 IPv4 - 谢谢 regex

选项 2(确保您获得 IPv4):

nslookup example.com 2>/dev/null | sed 's/[^0-9. ]//g' | tail -n 1 | awk -F " " '{print }'

解释:

nslookup example.com 2>/dev/null - 查找给定主机并忽略 STDERR (2>/dev/null)

sed 's/[^0-9. ]//g' - 获取 IPv4 的正则表达式(数字和点,阅读 's' 命令 here

tail -n 1 - 获取最后 1 行 (alt, tail -1)

awk -F " " '{print } - 使用“”作为字段分隔符捕获并打印行的第二部分

编辑: 根据评论稍作修改,使其实际上更通用:

nslookup example.com 2>/dev/null | printf "%s" "$(sed 's/[^0-9. ]//g')" | tail -n 1 | printf "%s" "$(awk -F " " '{print }')"

在上面的编辑中,我使用 printf 命令替换来处理任何不需要的尾随换行符。

这是我从早期答案中窃取的变体:

nslookup blueboard 2> /dev/null | awk '/Address/{a=}END{print a}'

这取决于 nslookup 返回的匹配行,如下所示:

Address 1: 192.168.1.100 blueboard

...只有 returns 最后一个地址。

警告:这根本不处理 non-matching 个主机名。