如何使用终端命令只获取IP地址而不包括其他信息?

183

我正在尝试在我编写的脚本中将IP地址(inet)作为参数使用。

在Unix终端中,是否有一种简单的方法可以仅获取IP地址,而不必查看ifconfig


是的,或者我猜可以使用任何其他关于机器的唯一标识符。 - Mason
1
你在使用 hostname -i 命令时遇到了无效选项? - Ken
是的,在Mac OS X Lion上。但事实证明我将在Ubuntu上完成它,那里它可以工作。谢谢! - Mason
4
主机名不如ifconfig可靠。 - joel
2
Joel是正确的,特别是当你谈论MAC OS和Ubuntu时。 - zackaryka
2
当浏览下面的答案时,请记住,“ip -o address”的输出比“ip address”的输出更易于处理。 - jlh
36个回答

230
你可以编写一个只返回IP地址的脚本,例如:
/sbin/ifconfig eth0 | grep 'inet addr' | cut -d: -f2 | awk '{print $1}'

对于MAC操作系统:

ifconfig | grep "inet " | grep -v 127.0.0.1 | cut -d\  -f2

或者对于Linux系统

hostname -i | awk '{print $3}' # Ubuntu 

hostname -i # Debian

6
在我的电脑上运行 hostname -i 命令会返回以下结果:::1 127.0.1.1 192.168.1.100 - Book Of Zeus
1
在Debian上,我只得到了一个IP地址。因此,使用“hostname”不是可移植的。 - Timofey Stolbov
1
它说-i和-I选项都是非法的。 - Mason
5
总之,第一种方法取决于适配器,而适配器并不总是相同的。对我来说,第二个方法显示了两个IP地址,而最后两个在Mac上无法使用。 - Matt
5
ifconfig已经过时且不可靠,例如,在Debian 9(Stretch)上grep失败,因为它不再输出“inet addr:172.17.0.4”,而只输出“inet 172.17.0.4”。请改用“ip”,如https://dev59.com/9Woy5IYBdhLWcg3wdt4L#26694162所述。 - jamshid
显示剩余13条评论

111

这将会提供给你所有的IPv4接口,包括回环地址127.0.0.1:

ip -4 addr | grep -oP '(?<=inet\s)\d+(\.\d+){3}'

这将仅显示eth0

ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'

您可以通过以下方式获取IPv6地址:

ip -6 addr | grep -oP '(?<=inet6\s)[\da-f:]+'

仅限 eth0 的IPv6:

ip -6 addr show eth0 | grep -oP '(?<=inet6\s)[\da-f:]+'

1
几乎每个生产环境的Docker容器上都没有安装grep。所以虽然这些命令都很好,但在容器上却无法使用 :-( - AndyGee
2
对于我的特定情况,最佳答案是使用Perl正则表达式的-P开关,否则我们无法使用后顾(?<=inet\s)标记。您可以通过运行grep -oe 'inet [0-9\.]\+'grep -oe 'inet6 [0-9a-f:]\+'来获得类似的结果,但这样我无法摆脱第一个单词。在SuSE中,man grep报告-P标志是实验性的。 - Jorge Bellon
4
第二个命令的简短版本:ip -4 a show eth0 | grep -Po 'inet \K[0-9.]*'。该命令用于显示eth0网络接口的IPv4地址。 - tukusejssirs
1
当使用 -br(简洁)开关的 ip 命令时,您可以摆脱正则表达式: ip -4 -br addr show eth0 | awk '{print $3}' - isp_developer
1
grep 带 -P 选项以及 ip 带 -br 选项在一些地方无法使用(如 alpine),但以下命令可以在所有环境中使用: ip -4 a show eth0 | awk '/inet/ {gsub(/\/\S+$/,"",$2) ; print $2}' - krad
显示剩余2条评论

63

通常情况下,系统不一定只有一个IP地址,例如,你可以同时拥有以太网和无线网络连接,如果你还有一个活跃的VPN连接,那么你会有另一个IP地址。

Linux

在Linux上,hostname -I命令将列出当前的IP地址(们)。依赖它总是返回一个IP地址很可能在某些情况下无法按预期工作(例如:VPN链接已建立,多个以太网适配器等),因此更可靠的方法是将结果转换为数组,然后遍历其中的元素:

ips=($(hostname -I))

for ip in "${ips[@]}"
do
    echo $ip
done

注意:如果 hostname -I 返回 IPv4 和 IPv6 格式的 IP,则可以使用 hostname -I | cut -f1 -d' ' 仅显示 IPv4 IP。

OSX

在 OSX 上,如果您知道接口,则可以使用:

~$ ipconfig getifaddr en0
# OUTPUT: 192.168.1.123

它将仅返回IP地址。

在MacOS上动态检测(第一个)活动的网络接口:

network_device=$(scutil --dns |awk -F'[()]' '$1~/if_index/ {print $2;exit;}')
ip=$(ipconfig getifaddr "$network_device")
echo $ip
### OUTPUT: 192.168.1.123 

此外,如果一台机器有多个以太网接口、同时建立了有线和wifi连接,或者VPN隧道已经建立,获取IP地址可能变得不确定。

获取外部IP

如果您需要获取外部IP地址,那么可以查询文本模式服务。例如,curl https://ipecho.net/plain将返回纯文本的外部 IP。

一个可能更快的替代方法是查询已知的DNS服务器,例如:

dig @ns1-1.akamaitech.net ANY whoami.akamai.net +short

如何获得局域网IP地址? - xkeshav
如果你想在Linux上将IP地址按行分隔,你不需要使用for循环,只需执行hostname -I | xargs -rn1 echo即可。 - Mikko Rantalainen

27
hostname -I  

这个命令可以在Ubuntu中给出你想要的精确IP地址。请注意,标志是大写


与已经存在的(并且得到高票)答案相比,我不认为这个答案会增加任何价值... - Mischa
4
在Centos上,使用命令"hostname -I"(大写的i)可以查看主机的IP地址。 - zzapper
1
这实际上帮了我 - 注意到大写字母'I'是关键。 - ChronoFish
3
一样的,这个工具完美地完成了工作,不需要额外的工具,也不需要调用十五个二进制文件来清理输出。谢谢! - Ulrar
"hostname" 不如 "ifconfig" 可靠,"-I" 选项的 manpage 中写道:"不要对输出的顺序做任何假设。" - Filip Seman

15

要在 Mac OS X 上仅获取IP地址,您可以输入以下命令:

ipconfig getifaddr en0

15

在最新的Ubuntu版本(14.04 - 16.04)中,这个命令对我有用。

hostname -I | awk '{print $1}'

5
从手册页面中可以得知:"[...] 此选项会列举出所有网络接口上配置的地址。[...] 不要对输出结果的顺序作任何假设"。最后一句话告诉你print $1可能会或者不会给出正确的结果。 - 9769953
不好的解决方案,因为主机名通常绑定到环回接口,那么在多宿主环境中如何工作呢? - krad

10

如果你的环境受限,可以使用以下命令:

ip -4 addr show dev eth0 | grep inet | tr -s " " | cut -d" " -f3 | head -n 1

5
甚至可以这样: ip -o -4 addr show dev eth0 | cut -d' ' -f7 | cut -d'/' -f1该命令的作用是显示eth0网络接口的IPv4地址,并将其截取为不包含子网掩码长度的形式。 - Jose Alban
是的,您是正确的。但要注意,如果eth0有多个IP地址,则会显示所有这些地址。 - caglar
bash-4.4# ip -4 addr show dev eth0 | grep inet | tr -s " " | cut -d" " -f3 | head -n 1172.17.0.3/16所以不太懂 /16 是什么意思。 - AndyGee
在循环中添加一个:ip -4 addr show eth0 | grep inet | awk '{print $2}' | cut -d'/' -f1。 对于v4和v6都是:ip addr show eth0 | grep inet | awk '{print $2}' | cut -d'/' -f1 - Sumit Murari
如果接口名称未知(或在平台之间不同),但您搜索私有IP地址,则应执行以下操作而不是ip -4 addr show eth0 | grep inetip -4 addr show | grep 192 - cyberbird
这也可以运行: ip -4 address show eth0 | awk '/inet/{split($2,a,"/");print a[1];exit}' - sparks

10

我不喜欢在脚本中使用awk等工具,ip有输出JSON的选项。

如果省略$interface参数,则会显示所有IP地址:

ip -json addr show $interface | \
  jq -r '.[] | .addr_info[] | select(.family == "inet") | .local'

我喜欢像ip命令一样以json结构格式显示命令结果的方式。以下是另一种类似于上面的获取IP地址的方法:ip -j addr show eth0 | jp "[0].addr_info[?family== 'inet'].local | [0]" - Jack Liu Shurui
请注意,此操作仅适用于新版本。例如,不适用于CentOS 7.5。 - Jean Spector
1
Debian 11 到了。感谢 -j 指针(你知道的越多)。我的方法是:ip -json -pretty -family inet addr show scope global | sed -n '/local/{s/[^0-9.]//g;p;q}'。这将打印具有全局范围(不包括回环)的第一个接口的 IPv4 地址。另一种方法没有使用 sed:ip -json -pretty -family inet addr show scope global | grep -m 1 local | tr -d -c 0-9.。最后,如果可以的话,您可能想尝试一下 jq,它是处理 ip 输出的非 hacky 方法(终于有一个 tokenizer):ip -json -family inet addr show scope global | jq -r '.[0].addr_info[0].local' - pupitetris
@pupitetris 关于scope global的建议很有用。在许多情况下,省略jq中的0索引是可取的。如果存在多个IP地址,则每行将获得一个IP地址:ip -json -family inet addr show scope global | jq -r '.[].addr_info[].local' - pabouk - Ukraine stay strong

6

在 Linux 上,ifconfig 命令已被弃用,应该使用 ip 命令。

此外,ip a 命令可以在同一行上提供 IP 的范围,更易于使用。

这个命令将显示您的全局(外部)IP:

ip a | grep "scope global" | grep -Po '(?<=inet )[\d.]+'

所有IPv4地址(包括127.0.0.1):

ip a | grep "scope" | grep -Po '(?<=inet )[\d.]+'

所有IPv6地址(也包括 ::1):
ip a | grep "scope" | grep -Po '(?<=inet6 )[\da-z:]+'

请注意,最后两个命令可能会返回多个IP。如果您想要默认路由的IP,则需要进行更多的过滤。 - Mikko Rantalainen

6

ip -4 addr show eth0 在某些机器上无法正常工作。例如,我会收到以下错误:

ip: symbol lookup error: ip: undefined symbol: bpf_program__section_name, version LIBBPF_0.2.0

这个命令对我有效:

/sbin/ifconfig eth0 | grep 'inet ' | awk '{ print $2}'

这个答案比被接受的答案少了一个管道符。此外,我的ifconfig输出中没有 inet addr

要获取IPv6地址,请使用以下命令:

/sbin/ifconfig eth0 | grep 'inet6 ' | awk '{ print $2}'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接