如何获取我自己的 IP 地址并将其保存到 shell 脚本中的变量中?

The*_*ent 91 networking ip shell-script

如何获取我自己的 IP 地址并将其保存到 shell 脚本中的变量中?

jsb*_*ngs 85

我相信获取 ipv4 地址的“现代工具”方法是解析“ip”而不是“ifconfig”,所以它会是这样的:

ip4=$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1)
ip6=$(/sbin/ip -o -6 addr list eth0 | awk '{print $4}' | cut -d/ -f1)
Run Code Online (Sandbox Code Playgroud)

或类似的东西。

  • `ip` 在我使用过的所有 Red Hat 和 Fedora 发行版上都可用。`ip` 是 iproute2 包 (http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2) 的一部分。`ifconfig` 和 `route` 应该被弃用,尽管它们继续被很多人使用,特别是在脚本中。在我看来,`ip` 更易于解析。 (5认同)
  • `ip` 也适用于我见过的所有 Debian 和基于 Debian 的发行版。它是 iproute 包的一部分,被标记为重要。 (3认同)
  • @jsbillings 为什么是 `/sbin/ip` 而不是 `ip`? (3认同)
  • 这是一个很好的答案!`awk` 和 `cut` 的组合对我来说有点有趣,这里有一个可能的替代方案,但实际上可能不会更好:`ip -o -4 addr show eth0 | awk '{ split($4, ip_addr, "/"); 打印 ip_addr[1] }'` (3认同)
  • 这绝对是应该如何完成的,我会否决其他答案以使用 ifconfig。`ip` 是 iproute2 包的一部分,默认情况下它是许多发行版。它在大多数好的回购中。http://en.wikipedia.org/wiki/Iproute2 (2认同)

And*_*rei 47

为什么不干脆做IP=$(hostname -I)

  • `hostname -i` 只给我 `127.0.0.1`,`hostname -I` 给我正确的 IP 地址... (4认同)
  • FreeBSD 上没有 `-I`,但你可以使用 `dig +short \`hostname -f\`` (4认同)
  • `hostname -I` 给了我两个以空格分隔的 IP。使用`CentOS 7.3.1611` (2认同)
  • @amphibient:是的,这是标准的。根据其文档,它返回主机配置的所有 IP 地址(环回和本地链路地址除外)。只能看到一个 IP 地址的人必须在只有一个非环回接口的主机上运行它。 (2认同)
  • “主机名-I”仍然允许歧义。我有很多docker网络,因此我看到:`192.168.0.33 192.168.1.106 192.168.16.1 172.23.0.1 172.17.0.1 172.24.0.1 172.26.0.1 172.18.0.1 172.27.0.1 2a02 :8108:41bf:c4b0::3c00 2a02:8108:41bf:c4b0:94ab:8d54:b734:1cb0 2a02:8108:41bf:c4b0:d1bb:4aa7:7cce:b458 ` 只有此列表中的第一个 IP 是我想要的,但我可以信任该 IP为了永远正确? (2认同)

l0b*_*0b0 39

如果您想考虑 wlan 和其他替代接口,这并不容易。如果你知道你想要哪个接口的地址(例如,eth0,第一个以太网卡),你可以使用这个:

ip="$(ifconfig | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"
Run Code Online (Sandbox Code Playgroud)

换句话说,给我网络配置信息,查找eth0,获取该行和下一行(-A 1),获取最后一行,在拆分时获取该行的第二部分:,然后在拆分时获取该行的第一部分与空间。

  • ifconfig 已弃用,您应该使用 `ip address` 代替 (8认同)
  • 您可以使用 `ifconfig eth0` 跳过第一个 grep (6认同)
  • 我在您的代码中添加了一个额外的 `grep`,以忽略其中包含“eth0:”的任何接口;这现在按我的预期工作(仅提供“eth0”IP 地址,而不提供任何子接口(eth0:0、eth0:1 等):`ip="$(ifconfig | grep -v 'eth0:' | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"` (2认同)

der*_*ert 30

如果你想要一个接口的地址,最简单的方法是安装 moreutils 然后:

anthony@Zia:~$ ifdata -pa br0
172.16.1.244
Run Code Online (Sandbox Code Playgroud)

ifdata几乎可以回答您想解析ifconfig输出的所有问题。

如果您想找出外界看到的 IP 地址(超越任何 NAT 等),有很多服务可以做到。一个相当简单:

anthony@Zia:~$ curl ifconfig.me
173.167.51.137
Run Code Online (Sandbox Code Playgroud)

  • ifdata 很好,但它不支持 ipv6。 (2认同)

Mik*_*kel 19

要获取 IPv4 和 IPv6 地址,而不假设主界面是eth0(这些天em1 更常见),请尝试:

ips=$(ip -o addr show up primary scope global |
      while read -r num dev fam addr rest; do echo ${addr%/*}; done)
Run Code Online (Sandbox Code Playgroud)
  • -o使用该一个行输出格式,这是更容易处理用readgrep等。
  • up 排除未激活的设备
  • scope global不包括私有/本地地址,例如127.0.0.1fe80::/64
  • primary排除临时地址(假设您想要一个不变的地址)

  • 这必须是最好的答案,因为 1)它不假设设备名称,2)它使用“ip”而不是老派的“ifconfig”,3)它也支持 ipv6。 (2认同)

Bru*_*sky 17

我不是想成为一个混蛋,但确实有一个正确的方法,就是这样。您可以修剪 的输出ip route以仅获取源 IP。根据您尝试访问的 IP,“我自己的 IP 地址”(OP 的话)会有所不同。如果您关心访问公共互联网,使用 Google 的 8.8.8.8 DNS 服务器是非常标准的。所以...

简短的回答是:

ip route get 8.8.8.8 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
Run Code Online (Sandbox Code Playgroud)

这是详细的解释

如果我想要我用来访问互联网的 ip ,我使用这个:

pi@et3:~ $ ip route get 8.8.8.8 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
10.55.0.200
Run Code Online (Sandbox Code Playgroud)

如果我想要使用 ip 访问我的VPN上的某些东西,我使用这个:

pi@et3:~ $ ip route get 172.31.0.100 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
172.29.0.9
Run Code Online (Sandbox Code Playgroud)

下一个实际上只是为了说明目的。但是,它应该适用于任何 Linux 系统。因此,您可以使用它来证明,是的,所有机器始终都有多个 IP 地址。

如果我想要我用来联系自己的 ip ,我会使用这个:

pi@et3:~ $ my_ip=$(getent hosts $(cat /etc/hostname) | awk '{print $1; exit}')
pi@et3:~ $ ip route get $my_ip | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
127.0.0.1
Run Code Online (Sandbox Code Playgroud)

有关该sed命令的更多信息

首先让我说,在选择unix工具时,您尽量选择需要最少管道的工具。因此,虽然有些答案会ifconfig传递grepsedto head,但这很少是必要的。当您看到它时,它应该发出一个危险信号,表明您正在听取经验不足的人的建议。这不会使“解决方案”出错。但是,它可能可以使用一些精简。

我选择sed它是因为它比awk. (我有下面的 awk 示例。)我认为没有任何其他工具,但那些 2 是合适的。

让我们来看看有什么sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'作用:

ip route get 8.8.8.8 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
Run Code Online (Sandbox Code Playgroud) 笔记:

我曾经使用过,sed -n '/src/{s/.*src *//p;q}'但一位评论者指出,有些系统在src字段之后有尾随数据。

使用 awk

ip route get 8.8.8.8 | \
    awk '{gsub(".*src",""); print $1; exit}'

# or

ip route get 8.8.8.8 | \
    awk '{for(i=1; i<NF; i++){if($i=="src"){i++; print $i; exit}}}'
Run Code Online (Sandbox Code Playgroud)

更多关于我的网络

我的ifconfig显示我有tun0我的 VPN 和eth0我的局域网。

pi@et3:~ $ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.55.0.200  netmask 255.255.252.0  broadcast 10.55.3.255
        inet6 fe80::71e6:5d7c:5b4b:fb25  prefixlen 64  scopeid 0x20<link>
        ether b8:27:eb:b2:96:84  txqueuelen 1000  (Ethernet)

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1  (Local Loopback)

tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1500
        inet 172.29.0.9  netmask 255.255.255.255  destination 172.29.0.10
        inet6 fe80::3a8e:8195:b86c:c68c  prefixlen 64  scopeid 0x20<link>
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 100  (UNSPEC)

wlan0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether b8:27:eb:e7:c3:d1  txqueuelen 1000  (Ethernet)
Run Code Online (Sandbox Code Playgroud)

  • @wisbucky 我受不了了。我也让我的 sed 与你的环境一起工作。 (3认同)
  • @wisbucky 我从不通过管道将 sed/awk/grep 在记录的代码中相互传输。(当我匆忙时,我会在命令行上使用它,但除了在我的 ~/.bash_history 中,你永远不会发现它被写入磁盘)我更新了使用 awk 的答案,它解决了这个问题。 (2认同)

Sté*_*las 10

取决于您所说的自己的 IP 地址是什么意思。系统在多个子网(有时每个子网有多个)上有 IP 地址,其中一些是 IPv4,一些 IPv6 使用以太网适配器、环回接口、VPN 隧道、网桥、虚拟接口等设备......

我的意思是另一个给定设备可以访问您的计算机的 IP 地址,您必须找出这是哪个子网,以及我们正在谈论的 IP 版本。另外,请记住,由于防火墙/路由器执行 NAT,接口的 IP 地址可能与远程主机看到的来自您的计算机的传入连接不同。

当有花哨的源路由或每个协议/端口路由时,可能很难找出哪个接口将用于通过给定的协议与一台远程计算机通信,即使如此,也不能保证该接口的 IP 地址可能是可以由想要与您的计算机建立新连接的远程计算机直接寻址。

对于 IPv4(可能也适用于 IPv6),在包括 Linux 在内的许多 unice 中都能找到用于访问给定主机的接口的 IP 地址的技巧是在 UDP 套接字上使用 connect(2) 并使用 getsockname ():

例如,在我的家用电脑上:

perl -MSocket -le 'socket(S, PF_INET, SOCK_DGRAM, getprotobyname("udp"));
connect(S, sockaddr_in(1, inet_aton("8.8.8.8")));
print inet_ntoa((sockaddr_in(getsockname(S)))[1]);'
Run Code Online (Sandbox Code Playgroud)

将用于找出我将到达 8.8.8.8(谷歌的 DNS 服务器)的接口的 IP 地址。它会返回类似于“192.168.1.123”的内容,这是到互联网的默认路由的接口地址。但是,谷歌不会将来自我机器的 DNS 请求视为来自该私有 IP 地址,因为我的家庭宽带路由器执行了 NAT。

connect() 在 UDP 套接字上不发送任何数据包(UDP 是无连接的),而是通过查询路由表来准备套接字。

在 Linux 上,使用最新版本的iproute2json 解析工具,例如jq,您应该能够获得相同的结果:

ip    -j route get 8.8.8.8              | jq -r '.[].prefsrc' # IPv4
ip -6 -j route get 2001:4860:4860::8888 | jq -r '.[].prefsrc' # IPv6
Run Code Online (Sandbox Code Playgroud)


fas*_*aan 8

ipa=$(ip route get 8.8.8.8| grep src| sed 's/.*src \(.*\)$/\1/g')

ipa=$(hostname -i|cut -f2 -d ' ')
Run Code Online (Sandbox Code Playgroud)

  • 如果“grep”还不够,请不要将其通过管道传递给其他东西。只需使用其他东西(“sed”、“awk”等)。 (2认同)

Tom*_*Tom 5

因为我认为没有人在这里提到过这个选项:

$ ip -f inet -json addr list | jq -r '.[] | select(length>0) | .addr_info[].local'
Run Code Online (Sandbox Code Playgroud)

解释:

ip可以生成 JSON 输出,然后您可以使用 进行查询jq.[]表示“返回的数组的每个成员”。 select(length>0)功能与它所说的差不多,但只有在您指定接口名称时才真正有用ip,在这种情况下,它会为每个不匹配的接口返回空对象。 表示打印.addr_info[].local在.addr_infoselect

值得查看一下 的输出,ip -json addr list | jq .看看您可以通过这种方式查询哪些其他信息。

编辑这也会返回环回地址。如果你不想这样:

$ ip -f inet -json addr list | jq -r '.[] | select(length>0) | select(.flags | index("LOOPBACK") | not) | .addr_info[].local'
Run Code Online (Sandbox Code Playgroud)

但请注意,许多系统仍会返回许多 IP 地址,并且如何判断哪个是“正确的”地址并不明显。例如,我的系统返回大约十几个地址,大部分是由 Docker 创建的。

如果“我自己的 IP 地址”是指您访问互联网的本地接口上的 IPv4 地址,请尝试以下操作:

$ my_ip=$(ip -j route get 8.8.8.8 | jq -r '.[0].prefsrc')
Run Code Online (Sandbox Code Playgroud)

ip -j route get 8.8.8.8正在询问内核,“假设我想将数据包发送到位于 8.8.8.8 的主机;您将如何将其发送到那里?” 8.8.8.8 是 Google 的 DNS 服务器,因此您很可能会通过互联网连接访问它。

jq -r '.[0].prefsrc'是将附加到数据包的源地址。

如果您没有互联网连接,my_ip此后将为空。您还可以明确检查这一点:

route_info=$(ip -j route get 8.8.8.8)
if [[ ! $? ]]; then
  echo "You have no internet connection."
  exit
fi
my_ip = $(echo ${route_info} | jq -r '.[0].prefsrc')
Run Code Online (Sandbox Code Playgroud)