如何获得自己的IP地址并将其保存到Shell脚本中的变量中?
如何获得自己的IP地址并将其保存到Shell脚本中的变量中?
Answers:
如果要考虑无线局域网和其他替代接口,这并非易事。如果您知道要使用哪个接口的地址(例如eth0,第一个以太网卡),则可以使用以下命令:
ip="$(ifconfig | grep -A 1 'eth0' | tail -1 | cut -d ':' -f 2 | cut -d ' ' -f 1)"
换句话说,获取我的网络配置信息,查找eth0
,获取该行和下一个(-A 1
),仅获取最后一行,使用进行拆分时获取该行的第二部分:
,然后在拆分时获取该行的第一部分。与空间。
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)"
ifconfig eth0
ip address
改用
我相信获取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)
或类似的东西。
ip
在我使用过的所有Red Hat和Fedora发行版中都可用。 ip
是iproute2软件包(linuxfoundation.org/collaborate/workgroups/networking/iproute2)的一部分。 ifconfig
并且route
据称已被弃用,尽管很多人继续使用它们,尤其是在脚本中。 ip
在我看来,更可解析。
ip
我所见过的所有基于Debian和Debian的发行版中也提供了该功能。它是iproute软件包的一部分,被标记为重要。
ip
是iproute2软件包的一部分,默认情况下是许多发行版。这是最有效的解决方案。 en.wikipedia.org/wiki/Iproute2
/sbin/ip
而不是ip
?
awk
,并cut
为轻度有趣对我来说,这里是它实际上可能没有更好的一种可能的选择:ip -o -4 addr show eth0 | awk '{ split($4, ip_addr, "/"); print ip_addr[1] }'
为什么不简单地做IP=$(hostname -I)
呢?
hostname -i
给我公正127.0.0.1
,hostname -I
给我正确的IP地址...
-i Display the network address(es) of the host name. Note that this works only if the host name can be resolved. Avoid using this option; use hostname --all-ip-addresses
/etc/hosts
,与相应的IP地址一起
-I
在FreeBSD上没有,但是您可以使用dig +short `hostname -f`
如果您想要接口的地址,最简单的方法是安装moreutils,然后:
anthony@Zia:~$ ifdata -pa br0
172.16.1.244
ifdata
几乎可以回答您想解析ifconfig
输出的每个问题。
如果您想在外面看到IP地址(除了任何NAT等),便可以找到很多服务。一个很简单:
anthony@Zia:~$ curl ifconfig.me
173.167.51.137
ifdata
添加到中会很好iproute2
。也许是一个称为“ ipdata
要获取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)
-o
使用该一个行输出格式,这是容易与处理read
,grep
等up
排除不活动的设备scope global
排除私有/本地地址,例如127.0.0.1
和fe80::/64
primary
排除临时地址(假设您想要一个不变的地址)-4
/ -6
过滤地址类型。您还可以轻松获取其他接口参数。就个人而言,我不喜欢while循环,我更喜欢grep -o 'inet6\? [0-9a-f\.:]*' | cut -f 2 -d ' '
取决于您自己的IP地址的含义。系统在几个子网中都有IP地址(有时每个子网有几个IP地址),其中一些是IPv4,一些使用诸如以太网适配器,环回接口,VPN隧道,网桥,虚拟接口等设备的IPv6 ...
我的意思是,另一个给定设备可以通过该IP地址访问您的计算机,您必须查明是哪个子网以及我们正在讨论的IP版本。另外,请记住,由于防火墙/路由器执行NAT,接口的IP地址可能与远程主机看到来自您计算机的传入连接不同。
如果存在奇特的源路由或每个协议/端口路由,可能很难找出将使用哪个接口通过给定协议与一台远程计算机通信,即使如此,也无法保证该接口的IP地址可能是希望与您的计算机建立新连接的远程计算机可以直接寻址。
对于IPv4(可能也适用于IPv6),在包括Linux在内的许多大学中,找出用于到达给定主机的接口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]);'
将用于查找我将通过该接口到达8.8.8.8(Google的DNS服务器)的接口的IP地址。它将返回类似“ 192.168.1.123”的内容,这是默认路由到Internet的接口地址。但是,google不会看到来自我的计算机的DNS请求来自该IP地址(这是一个私有IP地址),因为我的家庭宽带路由器执行了NAT。
UDP套接字上的connect()不会发送任何数据包(UDP是无连接的),而是通过查询路由表来准备套接字。
ipa=$(ip route get 8.8.8.8| grep src| sed 's/.*src \(.*\)$/\1/g')
ipa=$(hostname -i|cut -f2 -d ' ')
-I
代替-i
会更好,因为您可能想忽略回送地址,因此最终命令将是ipa=$(hostname -I|cut -f1 -d ' ')
grep
还不够,请不要将其传递给其他对象。只需使用其他的东西(sed
,awk
,等)。
我并不是说要混蛋,但确实有正确的方法,就是这样。修剪输出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}'
如果我想要我用来连接互联网的IP ,请使用以下命令:
pi@et3:~ $ ip route get 8.8.8.8 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
10.55.0.200
如果我希望我使用的IP可以到达我的VPN上的某个地址,请使用以下命令:
pi@et3:~ $ ip route get 172.31.0.100 | sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
172.29.0.9
下一个实际上仅用于说明目的。但是,它可以在任何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
sed
命令的更多信息首先,我要说的是,在选择unix工具时,您尝试选择需要最少管道的工具。所以,虽然一些答案会管ifconfig
到grep
到sed
到head
,这很少需要。当您看到它时,它应该发出一个红旗,表示您正在从经验不足的人那里获取建议。这不会使“解决方案”出错。但是,它可能需要进行一些简化。
我之所以选择sed
,是因为它比中的相同工作流程更简洁awk
。(我从下面有一个awk的例子。)我认为没有其他工具,但那两个是合适的。
让我们研究一下sed -n '/src/{s/.*src *\([^ ]*\).*/\1/p;q}'
:
sed # the sed executable located via $PATH
-n # no output unless explicitly requested
' # begin the command space
/src/ # regex match the string 'src'
{ # begin a block of commands **
s/ # begin a substitution (match)
.*src * # match anything leading up to and including src and any number of spaces
\([^ ]*\) # define a group containing any number of non spaces
.* # match any trailing characters (which will begin with a space because of the previous rule).
/ # begin the substitution replacement
\1 # reference the content in the first defined group
/ # end the substitution
p # print (explicitly, remember) the result
; # designate the end of the command
q # quit
} # end the block of commands
' # end the command space
** all of which will be performed "on match"
- otherwise only the first command to following the match would be performed "on match"
- any other commands would be performed whether there was a match or not
注意:
我曾经使用过,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}}}'
我的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)
ip route get 8.8.8.8 | sed -n '/src/{s/.*src *//p;q}'
给我了10.1.2.3 uid 1002
。因此,我添加了追加| awk '{print $1}'
以仅保留IP地址。
我使用这种单线:
IP=$(/sbin/ifconfig | grep -e "inet:" -e "addr:" | grep -v "inet6" | grep -v "127.0.0.1" | head -n 1 | awk '{print $2}' | cut -c6-)
使用ifconfig
(广泛可用),不获取localhost
地址,不将您绑定到给定的接口名称,不考虑IPv6并尝试获取第一个可用网络接口的IP。
您应该使用ip
(而不是ifconfig
),因为它是当前的,已维护的,并且也许最重要的是出于脚本目的,它会产生一致且可解析的输出。以下是一些类似的方法:
如果您想要以太网接口的IPv4地址eth0
:
$ ip -4 -o addr show eth0 | awk '{print $4}'
192.168.1.166/24
作为脚本:
$ INTFC=eth0
$ MYIPV4=$(ip -4 -o addr show $INTFC | awk '{print $4}')
$ echo $MYIPV4
192.168.1.166/24
上面产生的输出采用CIDR表示法。如果不需要CIDR表示法,可以将其删除:
$ ip -4 -o addr show eth0 | awk '{print $4}' | cut -d "/" -f 1
192.168.1.166
IMHO“最优雅”的另一个选择是获取用于连接到指定远程主机的任何接口的IPv4地址(在本例中为8.8.8.8)。由@gatoatigrado提供此答案:
$ ip route get 8.8.8.8 | awk '{ print $NF; exit }'
192.168.1.166
作为脚本:
$ RHOST=8.8.8.8
$ MYIP=$(ip route get $RHOST | awk '{ print $NF; exit }')
$ echo $MYIP
192.168.1.166
这在具有单个接口的主机上可以很好地工作,但是更有利的是,在具有多个接口和/或路由规范的主机上也可以工作。
ip
会是我偏爱的方法,但这当然不是给这只猫剥皮的唯一方法。hostname
如果您喜欢更简单/更简洁的方法,则可以使用以下另一种方法:
$ hostname --all-ip-addresses | awk '{print $1}'
或者,如果您想要IPv6地址:
$ hostname --all-ip-addresses | awk '{print $2}'
有些命令在centos 6或7上运行,下面的命令在这两者上都运行,
#!/bin/sh
serverip=`/sbin/ifconfig eth0 | grep "inet" | awk '{print $2}' | awk 'NR==1' | cut -d':' -f2`
echo $serverip
grep | awk | awk
。行可以缩短为/sbin/ifconfig eth0 | awk '$1 == "inet" { print substr($2,6); next ; } '
dig @ns1.google.com -t txt o-o.myaddr.l.google.com +short | tr -d \"
您可以使用dig(1)
诸如-4
或-6
专门查找IPv4或IPv6地址的选项。Google会以TXT
类型记录的形式提供答案,当由提供者提供时,其周围会带有引号dig
。如果您想随后将变量与实用程序一起traceroute
使用,则必须使用tr(1)之类的东西来删除引号。
其他选项包括whoami.akamai.net
和myip.opendns.com
,它们用A
和AAAA
记录答复(而不是TXT
上面的示例,来自Google),因此,它们不需要删除引号:
dig -4 @ns1-1.akamaitech.net -t a whoami.akamai.net +short
dig -4 @resolver1.opendns.com -t any myip.opendns.com +short
dig -6 @resolver1.opendns.com -t any myip.opendns.com +short
这是一个示例脚本,该脚本使用上述所有选项来设置变量:
#!/bin/sh
IPANY="$(dig @ns1.google.com -t txt o-o.myaddr.l.google.com +short | tr -d \")"
GOOGv4="$(dig -4 @ns1.google.com -t txt o-o.myaddr.l.google.com +short | tr -d \")"
GOOGv6="$(dig -6 @ns1.google.com -t txt o-o.myaddr.l.google.com +short | tr -d \")"
AKAMv4="$(dig -4 @ns1-1.akamaitech.net -t a whoami.akamai.net +short)"
CSCOv4="$(dig -4 @resolver1.opendns.com -t a myip.opendns.com +short)"
CSCOv6="$(dig -6 @resolver1.opendns.com -t aaaa myip.opendns.com +short)"
printf '$GOOG:\t%s\t%s\t%s\n' "${IPANY}" "${GOOGv4}" "${GOOGv6}"
printf '$AKAM:\t%s\n$CSCO:\t%s\t%s\n' "${AKAMv4}" "${CSCOv4}" "${CSCOv6}"
如果你正在寻找一个私有IP地址,或一组分配给中的所有IP地址,你可以使用的某种组合ifconfig
(在BSD和GNU / Linux), ip addr
(在GNU / Linux), hostname
(选件-i
和-I
上GNU / Linux),netstat
看看发生了什么。
hostname -I >> file_name
这会做你想要的一切
hostname: invalid option -- 'l'
...