Linux和OS X如何获取本机主IP地址?

我正在寻找一个命令行解决方案,将返回我的主(第一个)IP地址的本地主机,而不是127.0.0.1

该解决方案至少适用于Linux (Debian和RedHat)和OS X 10.7+

我知道ifconfig在两个平台上都可用,但它的输出在这些平台之间不那么一致。

699868 次浏览

使用grepifconfig中过滤IP地址:

ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'

或者使用sed:

ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'

如果你只对某些接口感兴趣,比如wlan0、eth0等,那么:

ifconfig wlan0 | ...

你可以将你的.bashrc中的命令别名为创建,例如你自己的命令称为myip

alias myip="ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'"

一个更简单的方法是hostname -I (hostname -i用于旧版本的hostname,但请参阅注释)。但是,这仅适用于Linux。

Edited (2014-06-01 2018-01-09 2021-07-25)

从一段时间以前,我现在使用更新的 ip工具。但在下,我将简单地做:

read -r _{,} gateway _ iface _ ip _ < <(ip r g 1.0.0.0)

然后

printf '%-12s %s\n'  gateway $gateway iface $iface ip $ip
gateway      192.168.1.1
iface        eth0
ip           192.168.1.37

从那里,蒙版是:

while IFS=$' /\t\r\n' read lne lip lmask _;do
[ "$lne" = "inet" ] && [ "$lip" = "$ip" ] && mask=$lmask
done < <(ip a s dev $iface)


echo Mask is $mask bits.
Mask is 24 bits.

然后如果你想把你的掩码作为一个IP:

printf -v msk '%*s' $mask ''
printf -v msk %-32s ${msk// /1}
echo $((msk=2#${msk// /0},msk>>24)).$((msk>>16&255)).$((msk>>8&255)).$((msk&255))
255.255.255.0
< h2 id = "编辑- 2014 - 06 - 01 - 2018 - 01 - 09 - ca1x”>编辑(s < > 2014-06-01 < / s > 2018-01-09) < / h2 >

为了更强的配置,每个接口上配置了许多接口和许多IP,我写了一个纯bash脚本(不是基于127.0.0.1),用于查找基于default route的正确接口而且 IP。我把这个脚本贴在这个答案的最下面。

< h3 id = " intro-9cu0 " >介绍< / h3 >

由于两个操作系统默认都安装了,所以Mac和Linux都有一个bash提示:

使用LANG=C可以防止区域问题:

myip=
while IFS=$': \t' read -a line ;do
[ -z "${line%inet}" ] && ip=${line[${#line[1]}>4?1:2]} &&
[ "${ip#127.0.0.1}" ] && myip=$ip
done< <(LANG=C /sbin/ifconfig)
echo $myip

将此放入一个函数:

最小:

getMyIP() {
local _ip _line
while IFS=$': \t' read -a _line ;do
[ -z "${_line%inet}" ] &&
_ip=${_line[${#_line[1]}>4?1:2]} &&
[ "${_ip#127.0.0.1}" ] && echo $_ip && return 0
done< <(LANG=C /sbin/ifconfig)
}

简单的使用:

getMyIP
192.168.1.37

Fancy -tidy:

.
getMyIP() {
local _ip _myip _line _nl=$'\n'
while IFS=$': \t' read -a _line ;do
[ -z "${_line%inet}" ] &&
_ip=${_line[${#_line[1]}>4?1:2]} &&
[ "${_ip#127.0.0.1}" ] && _myip=$_ip
done< <(LANG=C /sbin/ifconfig)
printf ${1+-v} $1 "%s${_nl:0:$[${#1}>0?0:1]}" $_myip
}

用法:

getMyIP
192.168.1.37

或者,运行相同的函数,但带有参数:

getMyIP varHostIP
echo $varHostIP
192.168.1.37
set | grep ^varHostIP
varHostIP=192.168.1.37

注:不带参数,该函数在STDOUT上输出IP和换行符,带参数,什么都不打印,但是创建一个名为argument的变量,包含不带换行符的IP。

Nota2:这是在Debian上测试,LaCie黑客nas和MaxOs。如果这在你的环境下行不通,我将非常感兴趣的反馈!

这个答案的旧版本

(未删除,因为基于sed,而不是bash。)

警告:有一个关于区域设置的问题!

又快又小:

myIP=$(ip a s|sed -ne '/127.0.0.1/!{s/^[ \t]*inet[ \t]*\([0-9.]\+\)\/.*$/\1/p}')

爆炸(工作也是;)

myIP=$(
ip a s |
sed -ne '
/127.0.0.1/!{
s/^[ \t]*inet[ \t]*\([0-9.]\+\)\/.*$/\1/p
}
'
)

编辑:

如何!这似乎不适用于Mac OS

好的,这似乎在Mac OS上的工作与在我的Linux上完全相同:

myIP=$(LANG=C /sbin/ifconfig  | sed -ne $'/127.0.0.1/ ! { s/^[ \t]*inet[ \t]\\{1,99\\}\\(addr:\\)\\{0,1\\}\\([0-9.]*\\)[ \t\/].*$/\\2/p; }')

容量:

myIP=$(
LANG=C /sbin/ifconfig  |
sed -ne $'/127.0.0.1/ ! {
s/^[ \t]*inet[ \t]\\{1,99\\}\\(addr:\\)\\{0,1\\}\\([0-9.]*\\)[ \t\/].*$/\\2/p;
}')

我的脚本(2018年1月):

这个脚本将首先找到用于的默认路由接口,然后搜索网关的本地ip匹配网络并填充变量。最后两行输出,如下所示:

Interface   : en0
Local Ip    : 10.2.5.3
Gateway     : 10.2.4.204
Net mask    : 255.255.252.0
Run on mac  : true

Interface   : eth2
Local Ip    : 192.168.1.31
Gateway     : 192.168.1.1
Net mask    : 255.255.255.0
Run on mac  : false

好吧,就是这样:

#!/bin/bash
runOnMac=false
int2ip() { printf ${2+-v} $2 "%d.%d.%d.%d" \
$(($1>>24)) $(($1>>16&255)) $(($1>>8&255)) $(($1&255)) ;}
ip2int() { local _a=(${1//./ }) ; printf ${2+-v} $2 "%u" $(( _a<<24 |
${_a[1]} << 16 | ${_a[2]} << 8 | ${_a[3]} )) ;}
while IFS=$' :\t\r\n' read a b c d; do
[ "$a" = "usage" ] && [ "$b" = "route" ] && runOnMac=true
if $runOnMac ;then
case $a in
gateway )    gWay=$b  ;;
interface )  iFace=$b ;;
esac
else
[ "$a" = "0.0.0.0" ] && [ "$c" = "$a" ] && iFace=${d##* } gWay=$b
fi
done < <(/sbin/route -n 2>&1 || /sbin/route -n get 0.0.0.0/0)
ip2int $gWay gw
while read lhs rhs; do
[ "$lhs" ] && {
[ -z "${lhs#*:}" ] && iface=${lhs%:}
[ "$lhs" = "inet" ] && [ "$iface" = "$iFace" ] && {
mask=${rhs#*netmask }
mask=${mask%% *}
[ "$mask" ] && [ -z "${mask%0x*}" ] &&
printf -v mask %u $mask ||
ip2int $mask mask
ip2int ${rhs%% *} ip
(( ( ip & mask ) == ( gw & mask ) )) &&
int2ip $ip myIp && int2ip $mask netMask
}
}
done < <(/sbin/ifconfig)
printf "%-12s: %s\n" Interface $iFace Local\ Ip $myIp \
Gateway $gWay Net\ mask $netMask Run\ on\ mac $runOnMac

不确定这是否适用于所有操作系统,尝试一下。

ifconfig | awk -F"[ :]+" '/inet addr/ && !/127.0/ {print $4}'

对于linux机器(不是OS X):

hostname --ip-address
ifconfig | grep "inet addr:" | grep -v "127.0.0.1" | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'  | head -1

只针对Ubuntu的某些版本。尽管它可能只告诉你127.0.0.1:

hostname  -i

hostname -I
ip addr show | grep -E '^\s*inet' | grep -m1 global | awk '{ print $2 }' | sed 's|/.*||'

linux下也可以通过该命令获取eth0的IP地址

/sbin/ip -4 -o addr show dev eth0| awk '{split($4,a,"/");print a[1]}'

输出如下所示

[root@localhost Sathish]# /sbin/ip -4 -o addr show dev eth0| awk '{split($4,a,"/");print a[1]}'
192.168.1.22

下面的代码可以在Linux上运行,但不能在OSX上运行。

这根本不依赖于DNS,即使/etc/hosts没有正确设置(11.0.0.0的缩写),它也能工作:

ip route get 1 | awk '{print $NF;exit}'

或避免awk,并使用谷歌的公共DNS 8.8.8.8

ip route get 8.8.8.8 | head -1 | cut -d' ' -f8

一种不太可靠的方式:(见下面的评论)

hostname -I | cut -d' ' -f1

在linux系统上获取本地ipv4地址的最短方法:

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

在Mac电脑上,考虑以下问题:

scutil --nwi | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'

如果你知道网络接口(eth0, wlan, tun0等):

ifconfig eth0 | grep addr: | awk '{ print $2 }' | cut -d: -f2

主网口IP

ifconfig `ip route | grep default | head -1 | sed 's/\(.*dev \)\([a-z0-9]*\)\(.*\)/\2/g'` | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" | head -1

这适用于Linux和OSX

这将获得与默认路由关联的接口

NET_IF=`netstat -rn | awk '/^0.0.0.0/ {thif=substr($0,74,10); print thif;} /^default.*UG/ {thif=substr($0,65,10); print thif;}'`

使用上面发现的接口,获取ip地址。

NET_IP=`ifconfig ${NET_IF} | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'`

OSX

uname -a

达尔文笔记本14.4.0达尔文内核版本14.4.0:Thu 5月28日11:35:04 PDT 2015;根:xnu-2782.30.5 ~ 1 / RELEASE_X86_64 x86_64

echo $NET_IF

en5

echo $NET_IP

192.168.0.130

Linux CentOS

uname -a

Linux dev-cil.medfx。当地2.6.18-164。el5xen 1 SMP Thu Sep 3 04:03:03 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux

echo $NET_IF

eth0

echo $NET_IP

192.168.46.10

另一个在Linux和OSX上都可以工作的ifconfig变体:

ifconfig | grep "inet " | cut -f2 -d' '
ifconfig $(netstat -rn | grep -E "^default|^0.0.0.0" | head -1 | awk '{print $NF}') | grep 'inet ' | awk '{print $2}' | grep -Eo '([0-9]*\.){3}[0-9]*'

我浏览了很多链接(StackExchange, AskUbuntu, StackOverflow等),并决定将所有最好的解决方案合并到一个shell脚本中。

在我看来,这两个qa是我见过的最好的:

如何在shell脚本中获得我的外部IP地址? https://unix.stackexchange.com/q/22615 < / p > 我如何找到我的内部ip地址? https://askubuntu.com/a/604691 < / p >

以下是基于rsp在他的存储库(https://github.com/rsp/scripts/)中分享的一些想法的解决方案。

有些人可能会说这个脚本对于这么简单的任务来说是非常大的,但我想让它在使用时尽可能地简单和灵活。它支持简单的配置文件,允许重新定义默认值。

它在Cygwin, MINGW和Linux (Red Hat)下成功测试。

显示内部IP地址

myip -i

显示外部IP地址

myip -e

源代码,也可以通过链接获得:https://github.com/ildar-shaimordanov/tea-set/blob/master/home/bin/myip。配置文件的示例在那里,在主脚本旁边。

#!/bin/bash


# =========================================================================
#
# Getting both internal and external IP addresses used for outgoing
# Internet connections.
#
# Internal IP address is the IP address of your computer network interface
# that would be used to connect to Internet.
#
# External IP address is the IP address that is visible by external
# servers that you connect to over Internet.
#
# Copyright (C) 2016 Ildar Shaimordanov
#
# =========================================================================


# Details of the actual implementation are based on the following QA:
#
# How can I get my external IP address in a shell script?
# https://unix.stackexchange.com/q/22615
#
# How do I find my internal ip address?
# https://askubuntu.com/a/604691


# =========================================================================


for f in \
"$( dirname "$0" )/myip.conf" \
~/.myip.conf \
/etc/myip.conf
do
[ -f "$f" ] && {
. "$f"
break
}
done


# =========================================================================


show_usage() {
cat - <<HELP
USAGE
$( basename "$0" ) [OPTIONS]


DESCRIPTION
Display the internal and external IP addresses


OPTIONS
-i  Display the internal IP address
-e  Display the external IP address
-v  Turn on verbosity
-h  Print this help and exit
HELP
exit
}


die() {
echo "$( basename "$0" ): $@" >&2
exit 2
}


# =========================================================================


show_internal=""
show_external=""
show_verbose=""


while getopts ":ievh" opt
do
case "$opt" in
i )
show_internal=1
;;
e )
show_external=1
;;
v )
show_verbose=1
;;
h )
show_usage
;;
\? )
die "Illegal option: $OPTARG"
;;
esac
done


if [ -z "$show_internal" -a -z "$show_external" ]
then
show_internal=1
show_external=1
fi


# =========================================================================


# Use Google's public DNS to resolve the internal IP address
[ -n "$TARGETADDR" ] || TARGETADDR="8.8.8.8"


# Query the specific URL to resolve the external IP address
[ -n "$IPURL" ] || IPURL="ipecho.net/plain"


# Define explicitly $IPCMD to gather $IPURL using another tool
[ -n "$IPCMD" ] || {
if   which curl >/dev/null 2>&1
then
IPCMD="curl -s"
elif which wget >/dev/null 2>&1
then
IPCMD="wget -qO -"
else
die "Neither curl nor wget installed"
fi
}


# =========================================================================


resolveip() {
{
gethostip -d "$1" && return
getent ahostsv4 "$1" \
| grep RAW \
| awk '{ print $1; exit }'
} 2>/dev/null
}


internalip() {
[ -n "$show_verbose" ] && printf "Internal: "


case "$( uname | tr '[:upper:]' '[:lower:]' )" in
cygwin* | mingw* | msys* )
netstat -rn \
| grep -w '0.0.0.0' \
| awk '{ print $4 }'
return
;;
esac


local t="$( resolveip "$TARGETADDR" )"
[ -n "$t" ] || die "Cannot resolve $TARGETADDR"
ip route get "$t" \
| awk '{ print $NF; exit }'
}


externalip() {
[ -n "$show_verbose" ] && printf "External: "


eval $IPCMD "$IPURL" $IPOPEN
}


# =========================================================================


[ -n "$show_internal" ] && internalip
[ -n "$show_external" ] && externalip


# =========================================================================


# EOF

我只是利用网络接口名称,我的自定义命令是

[[ $(ip addr | grep enp0s25) != '' ]] && ip addr show dev enp0s25 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p' || ip addr show dev eth0 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p'

在我自己的笔记本上

[flying@lempstacker ~]$ cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
[flying@lempstacker ~]$ [[ $(ip addr | grep enp0s25) != '' ]] && ip addr show dev enp0s25 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p' || ip addr show dev eth0 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p'
192.168.2.221
[flying@lempstacker ~]$

但如果网络接口拥有至少一个ip,那么它将显示属于它的所有ip

例如

Ubuntu 16.10

root@yakkety:~# sed -r -n 's@"@@g;s@^VERSION=(.*)@\1@p' /etc/os-release
16.04.1 LTS (Xenial Xerus)
root@yakkety:~# [[ $(ip addr | grep enp0s25) != '' ]] && ip addr show dev enp0s25 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p' || ip addr show dev eth0 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p'
178.62.236.250
root@yakkety:~#

Debian杰西

root@jessie:~# sed -r -n 's@"@@g;s@^PRETTY_NAME=(.*)@\1@p' /etc/os-release
Debian GNU/Linux 8 (jessie)
root@jessie:~# [[ $(ip addr | grep enp0s25) != '' ]] && ip addr show dev enp0s25 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p' || ip addr show dev eth0 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p'
192.81.222.54
root@jessie:~#

CentOS 6.8

[root@centos68 ~]# cat /etc/redhat-release
CentOS release 6.8 (Final)
[root@centos68 ~]# [[ $(ip addr | grep enp0s25) != '' ]] && ip addr show dev enp0s25 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p' || ip addr show dev eth0 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p'
162.243.17.224
10.13.0.5
[root@centos68 ~]# ip route get 1 | awk '{print $NF;exit}'
162.243.17.224
[root@centos68 ~]#

Fedora 24

[root@fedora24 ~]# cat /etc/redhat-release
Fedora release 24 (Twenty Four)
[root@fedora24 ~]# [[ $(ip addr | grep enp0s25) != '' ]] && ip addr show dev enp0s25 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p' || ip addr show dev eth0 | sed -n -r 's@.*inet (.*)/.*brd.*@\1@p'
104.131.54.185
10.17.0.5
[root@fedora24 ~]# ip route get 1 | awk '{print $NF;exit}'
104.131.54.185
[root@fedora24 ~]#

似乎由链接提供的命令ip route get 1 | awk '{print $NF;exit}'更准确,而且,它更短。

使用some of other方法您可能会输入系统中定义了多个IP地址的冲突。 这一行总是默认使用的IP地址

ip route get 8.8.8.8 | head -1 | awk '{print $7}'

适用于Mac, Linux和Docker容器内部:

$ hostname --ip-address 2> /dev/null || (ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p' | awk '{print 1美元;退出}”)

也适用于Makefile,如下:

LOCAL_HOST := ${shell hostname --ip-address 2> /dev/null || (ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p' | awk '{print $1; exit}')}

假设你需要你的主公共 IP,就像它从世界其他地方看到的那样,尝试其中任何一个:

wget http://ipecho.net/plain -O - -q
curl http://icanhazip.com
curl http://ifconfig.me/ip

对于linux,你需要的是这个命令:

ifconfig $1|sed -n 2p|awk '{ print $2 }'|awk -F : '{ print $2 }'

在你的shell中输入这个,你就会知道你的ip。

这更容易读: ifconfig | grep 'inet addr:' |/usr/bin/awk '{print $2}' | tr -d addr: < / p >

在Linux上

hostname -I

在macOS

ipconfig getifaddr en0

hostname -I可以以不可靠的顺序返回多个地址(参见hostname manpage),但对我来说,它只返回192.168.1.X,这是你想要的。

如果你已经安装了npmnode: npm install -g ip && node -e "const ip = require('ip'); console.log(ip.address())"

我必须补充科林安德森的回答,这个方法也考虑到如果你有两个界面,他们都显示为向上。

ip route get 1 | awk '{print $NF;exit}'

我一直在用树莓派(Raspberry Pi)开发一个应用程序,需要实际使用的IP地址,而不仅仅是它是否启动。大多数其他答案都会返回两个IP地址,这对我的场景来说不一定有帮助。

解决方案

$ ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p'
192.168.8.16

解释

查询网络信息的正确的方法是使用ip:

  • -o一行输出
  • route get to获取到目的地的实际内核路由
  • 8.8.8.8谷歌IP,但是可以使用你想要到达的真实IP

例如:ip输出:

8.8.8.8 via 192.168.8.254 dev enp0s25 src 192.168.8.16 uid 1000 \   cache

要提取src ip, sed是最轻的,与正则表达式支持最兼容:

  • -n默认无输出
  • 's/pattern/replacement/p'匹配模式和打印替换
  • .*src \([0-9.]\+\).*匹配内核使用的src IP,以达到8.8.8.8

例如,最终输出:

192.168.8.16

其他答案

我认为前面的答案对我来说都不够好,因为它们在最近的机器上不起作用(Gentoo 2018)。

我在前面的答案中发现的问题:

  • 在命令输出中使用位置列;
  • 使用已弃用的ifconfig,例如,不列出多个ip;
  • awk用于一个简单的任务,sed可以更好地处理;
  • ip route get 1是不清楚的,实际上是ip route get to 1.0.0.0的别名
  • 使用hostname命令,在所有设备中都没有-I选项,在我的情况下返回127.0.0.1

所有东西都有一个节点包。它是跨平台的,易于使用。

$ npm install --global internal-ip-cli


$ internal-ip
fe80::1


$ internal-ip --ipv4
192.168.0.3

这是一种有争议的方法,但不管你喜不喜欢,在工具中使用npm正变得越来越流行。

ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}'

我提取我对这个答案的评论:

ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'

它基于@CollinAnderson的答案,但对我来说没用。

在一个默认网关的网络中查找这台计算机的IP地址(例如排除所有虚拟网络,docker桥接器)。互联网网关,wifi网关,以太网

ip route| grep $(ip route |grep default | awk '{ print $5 }') | grep -v "default" | awk '/scope/ { print $9 }'

适用于Linux。

测试:

➜  ~ ip route| grep $(ip route |grep default | awk '{ print $5 }') | grep -v "default" | awk '/scope/ { print $9 }'
192.168.0.114


➜  reverse-networking git:(feature/type-local) ✗ ifconfig wlp2s0
wlp2s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
inet 192.168.0.114  netmask 255.255.255.0  broadcast 192.168.0.255
inet6 fe80::d3b9:8e6e:caee:444  prefixlen 64  scopeid 0x20<link>
ether ac:x:y:z  txqueuelen 1000  (Ethernet)
RX packets 25883684  bytes 27620415278 (25.7 GiB)
RX errors 0  dropped 27  overruns 0  frame 0
TX packets 7511319  bytes 1077539831 (1.0 GiB)
TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0