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)
或类似的东西。
And*_*rei 47
为什么不干脆做IP=$(hostname -I)?
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),只获取最后一行,在拆分时获取该行的第二部分:,然后在拆分时获取该行的第一部分与空间。
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)
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使用该一个行输出格式,这是更容易处理用read,grep等。up 排除未激活的设备scope global不包括私有/本地地址,例如127.0.0.1和fe80::/64primary排除临时地址(假设您想要一个不变的地址)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传递grep到sedto 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字段之后有尾随数据。
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)
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)
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)
因为我认为没有人在这里提到过这个选项:
$ 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)