455

I am looking for a command line solution that would return me the primary (first) IP address of the localhost, other than 127.0.0.1

The solution should work at least for Linux (Debian and RedHat) and OS X 10.7+

I am aware that ifconfig is available on both but its output is not so consistent between these platforms.

8
  • 2
    Do you just want your machine local network IP? i.e 192.168.0.12 Commented Nov 10, 2012 at 13:34
  • Yes, the local IP, first of them as it can have more than one, but I could live even with a list. For the moment I am happy to support only IPv4 addresses and ignore the IPv6, as want it only to generate a hash.
    – sorin
    Commented Nov 10, 2012 at 13:36
  • 2
    How do you define "primary"? If you're thinking "the IP address that's on the same subnet as my default route", you'll need to program a bit for that. But what if the machine has no default route, but still has >1 IP addresses?
    – ghoti
    Commented Nov 10, 2012 at 17:06
  • 11
    Try curl -4 ifconfig.co . It will answer with your external IP4 address.
    – asmaier
    Commented Aug 6, 2019 at 9:34
  • I've just used curl ifconfig.me and it worked fine. Commented Jan 20, 2021 at 15:06

31 Answers 31

599

Use grep to filter IP address from ifconfig:

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

Or with sed:

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

If you are only interested in certain interfaces, wlan0, eth0, etc. then:

ifconfig wlan0 | ...

You can alias the command in your .bashrc to create your own command called myip for instance.

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

A much simpler way is hostname -I (hostname -i for older versions of hostname but see comments). However, this is on Linux only.

19
  • 5
    Note also that in OSX, sed uses the -E option for Extended RE, not the GNU-style -r option.
    – ghoti
    Commented Nov 10, 2012 at 19:51
  • 1
    Interesting; I didn't realize that GNU sed supported -E. Recent versions of FreeBSD have added the -r option as an alias for -E to ease script portability, but the update hasn't yet been brought over to OSX, which last I checked still uses a version of sed from a FreeBSD release of a few years ago. Not sure precisely which one, as OSX has adoped FreeBSD source code a few times over the years. I believe the use of -E was intended to be comparable to grep's -E option. No idea why GNU folks opted for -r instead.
    – ghoti
    Commented Nov 10, 2012 at 20:00
  • 1
    @ghoti I changed answer to use -E to be sure of portability, you'd think that --help and the man pages would be updated.. it did cause slight confusion for me earlier in another question using -E Commented Nov 10, 2012 at 20:06
  • 3
    I found a problem, while this works on OS X it does return more than one IP, a list of IPs. It seems that the first one is the right one but still this would break my logic. See gist.github.com/ssbarnea/31b9dcb0f8fd528b958c -- it also returns the vnic ones that are active but used by paralles.
    – sorin
    Commented Aug 28, 2013 at 11:16
  • 20
    OSX: ipconfig getifaddr en0
    – parleer
    Commented Nov 16, 2015 at 5:12
304

The following will work on Linux but not OSX.

This doesn't rely on DNS at all, and it works even if /etc/hosts is not set correctly (1 is shorthand for 1.0.0.0):

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

or avoiding awk and using Google's public DNS at 8.8.8.8 for obviousness:

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

A less reliable way: (see comment below)

hostname -I | cut -d' ' -f1
22
  • 10
    The method that gets the first address produced by the hostname -I is unreliable, because (according to the documentation) one cannot make any assumptions about the order of the addresses. So it may well be some internal network (like the network on which virtual machines are living). The other method seems good. Commented Sep 23, 2014 at 23:27
  • 21
    For me ip route get 1 | awk '{print $(NF-2);exit}' works as I get uid appended to the outptut
    – Hritik
    Commented Sep 29, 2017 at 8:16
  • 15
    THIS (the first one) IS THE ONLY CORRECT SOLUTION. It is important to read the IP specifically from the interface associated with the default route. Otherwise you are quite likely to get some worthless internal address.
    – Jan Hudec
    Commented Mar 21, 2018 at 9:17
  • 26
    it didn't work for me but it was closed enough: ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'
    – estani
    Commented Jul 24, 2018 at 8:16
  • 7
    Seems like the output format of ip isn't quite stable. For me, cut -d' ' -f8 doesn't work, but cut -d' ' -f7 does.
    – brightbyte
    Commented Nov 16, 2018 at 17:27
264

For linux machines (not OS X) :

hostname --ip-address
10
  • 13
    That only works if the name is in DNS. If not, you get the message "hostname: Name or service not known." Commented Nov 10, 2013 at 5:21
  • 50
    hostname -i is the equivalent short form
    – Paul Evans
    Commented May 13, 2014 at 13:45
  • 88
    This will sometimes simply return 127.0.0.1. If available, better use hostname -I as recommended by the manual (Ubuntu): "--ip-address 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 instead."
    – jrierab
    Commented Jun 12, 2014 at 16:33
  • 8
    On my machine, hostname -i gives only the local IP, while hostname -I gives all the other IPs Commented Jul 21, 2017 at 6:42
  • 2
    This returned 127.0.0.1 on my machine
    – mitiko
    Commented Aug 4, 2017 at 18:39
106

Solution

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

Explanation

The correct way to query network information is using ip:

  • -o one-line output
  • route get to get the actual kernel route to a destination
  • 8.8.8.8 Google IP, but can use the real IP you want to reach

e.g. ip output:

8.8.8.8 via 192.168.8.254 dev enp0s25 src 192.168.8.16 uid 1000 \   cache

To extract the src ip, sed is the ligthest and most compatible with regex support:

  • -n no output by default
  • 's/pattern/replacement/p' match pattern and print replacement only
  • .*src \([0-9.]\+\).* match the src IP used by the kernel, to reach 8.8.8.8

e.g. final output:

192.168.8.16

Other answers

I think none of the preceding answer are good enough for me, as they don't work in a recent machine (Gentoo 2018).

Issues I found with preceding answers:

  • use of positional column in command output;
  • use of ifconfig which is deprecated and -- for example -- don't list multple IPs;
  • use of awk for a simple task which sed can handle better;
  • ip route get 1 is unclear, and is actually an alias for ip route get to 1.0.0.0
  • use of hostname command, which don't have -I option in all appliance and which return 127.0.0.1 in my case.
4
  • You could avoid fork to sed and become more detailed infos by using bash read! See my answer Commented Jul 26, 2021 at 7:19
  • This is the only solution that worked flawlessly for me in 2022 Commented Apr 6, 2022 at 17:14
  • not working. Option "-o" is unknown, try "ip -help". Commented Sep 27, 2022 at 9:34
  • In my ip implementation, -o is present and is a shortcut for -oneline
    – giosh94mhz
    Commented Oct 17, 2022 at 8:58
100

on Linux

hostname -I

on macOS

ipconfig getifaddr en0

hostname -I can return multiple addresses in an unreliable order (see the hostname manpage), but for me it just returns 192.168.1.X, which is what you wanted.

6
  • 2
    for me it was hostname -i with a lower I. Commented Nov 10, 2017 at 8:32
  • 4
    @PaulWoitaschek the manpage for the lowercase -i flag says this: Avoid using this option; use hostname -I instead.
    – user3064538
    Commented Nov 26, 2019 at 16:52
  • 1
    @Boris if you're running in something like a docker container running Alpine (and thus BusyBox) it will only accept lowercase -i flag
    – bayetovsky
    Commented Dec 30, 2019 at 17:51
  • hostname -I | grep -o "^[0-9.]*" If you just want the first one. Commented Sep 10, 2020 at 11:16
  • 1
    @landau en0 is Wi-Fi according to this answer.
    – user3064538
    Commented Apr 6, 2023 at 18:15
49

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

From some time ago, I use now newer ip tool. But under , I will do simply:

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

Then

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

From there, the mask is:

while IFS=$' /\t\r\n' read lne lip lmask _; do
    case $lne:$lip in "inet:$ip") masklen=$lmask; break ;; esac
done < <(ip a s dev $iface)

echo Mask is $masklen bits length.
Mask is 24 bits length.

( Note: I've replaced double test: [[ $ip = ... ]] && [[... by case condition, because of efficience and speedness more infos at stringContain!! )

Then if you want to see your mask as an IP:

printf -v mask '%*s' $masklen ''
printf -v mask %-32s ${mask// /1}
printf -v mask %d.%d.%d.%d $((mask=2#${mask// /0},mask>>24)) \
    $((mask>>16&255)) $((mask>>8&255)) $((mask&255))

Then showing all variables:

for var in ip mask gateway masklen iface; do
    printf '%-12s %s\n' $var ${!var}
done
ip           192.168.1.37
mask         255.255.255.0
gateway      192.168.1.1
masklen      24
iface        eth0

Edited (2014-06-01 2018-01-09)

For stronger config, with many interfaces and many IP configured on each interfaces, I wrote a pure bash script (not based on 127.0.0.1) for finding correct interface and ip, based on default route. I post this script at very bottom of this answer.

Intro

As both Os have installed by default, there is a bash tip for both Mac and Linux:

The locale issue is prevented by the use of 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

Putting this into a function:

Minimal:

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)
}

Simple use:

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
}

Usage:

getMyIP
192.168.1.37

or, running same function, but with an argument:

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

Nota: Without argument, this function output on STDOUT, the IP and a newline, with an argument, nothing is printed, but a variable named as argument is created and contain IP without newline.

Nota2: This was tested on Debian, LaCie hacked nas and MaxOs. If this won't work under your environ, I will be very interested by feed-backs!

Older version of this answer

( Not deleted because based on sed, not bash. )

Warn: There is an issue about locales!

Quick and small:

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

Exploded (work too;)

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

Edit:

How! This seem not work on Mac OS...

Ok, this seem work quite same on Mac OS as on my 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; }')

splitted:

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;
        }')

My script (jan 2018):

This script will first find your default route and interface used for, then search for local ip matching network of gateway and populate variables. The last two lines just print, something like:

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

or

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

Well, there it is:

#!/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
10
  • 1
    @sorin: yes, this work now with ifconfig. (as sbin is not on my $PATH fullpath have to be specified, but same path exist on MacOS too. :-) Commented Nov 10, 2012 at 15:10
  • 1
    @sorin try this with time to select which you would use so long... Commented Nov 10, 2012 at 20:25
  • the quick and small solution was the best approach. Newer solutions give me syntax errors. Compatibility is always a plus. Thank you.
    – m3nda
    Commented Mar 17, 2015 at 4:58
  • This does not show the public ip address , like curl ifconfig.me does
    – alper
    Commented Jul 25, 2021 at 15:32
  • @alper this is not the scope of request... And ifconfig.me is just another what-is-my-ip provider. Commented Jul 25, 2021 at 16:12
29

Specific to only certain builds of Ubuntu. Though it may just tell you 127.0.0.1:

hostname  -i

or

hostname -I
6
  • does this work in every case? Commented Mar 21, 2014 at 11:20
  • 9
    no. - it may just tell you 127.0.0.1. Commented May 9, 2014 at 4:00
  • hostname -I works on ubuntu.
    – Borzh
    Commented Oct 20, 2014 at 17:45
  • 3
    $ hostname --ip-address just gives me 127.0.0.1 on Arch Linux
    – kristianlm
    Commented Jun 11, 2015 at 7:56
  • 2
    use hostname -I or hostname --all-ip-addresses
    – Aydin K.
    Commented Mar 21, 2018 at 17:32
25

You can also get IP version 4 address of eth0 by using this command in linux

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

Output will be like this

[root@localhost Sathish]# /sbin/ip -4 -o addr show dev eth0| awk '{split($4,a,"/");print a[1]}'
192.168.1.22
2
  • This assumes eth0, which is not current naming strategy and never was guaranteed to be the primary interface.
    – rfay
    Commented May 29, 2019 at 17:04
  • This is the most elegant method if you know the interface. Ideal if your system has multiple interfaces but you are just interested in a particular one.
    – lepe
    Commented Dec 20, 2019 at 7:26
16

Using some of the other methods You may enter a conflict where multiple IP adresses is defined on the system. This line always gets the IP address by default used.

ip route get 8.8.8.8 | head -1 | awk '{print $7}'
2
  • It will fail if there is no default route (but good idea) Commented Jul 26, 2017 at 19:35
  • Nice... Suppose to work even if you don't have internet? Commented Dec 18, 2017 at 12:19
14

This works on Linux and OSX

This will get the interface associated to the default route

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;}'`

Using the interface discovered above, get the ip address.

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

Darwin laptop 14.4.0 Darwin Kernel Version 14.4.0: Thu May 28 11:35:04 PDT 2015; root:xnu-2782.30.5~1/RELEASE_X86_64 x86_64

echo $NET_IF

en5

echo $NET_IP

192.168.0.130

CentOS Linux

uname -a

Linux dev-cil.medfx.local 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

1
  • Despite all the answers to this question, this one appears to be the only one that comes close to actually being correct. Just needs a | head -1 at the end of the first line to get the default interface, and the rest is good.
    – Endareth
    Commented Mar 24, 2017 at 3:08
13
ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}'
5
  • 1
    If you're looking to make this into a bash alias: alias myip="ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print \$2}'" Commented Mar 10, 2019 at 10:44
  • Right. But the question initially was about the command. So I just posted relevantly. Cheers! Commented Mar 11, 2019 at 11:04
  • 1
    Don't understand why this answer has less likes. Simple & working!!! Commented Apr 14, 2021 at 3:08
  • Purely with awk, this would be: ifconfig | awk '/inet / {if($2=="127.0.0.1") {next}; print $2}'
    – mike
    Commented Aug 25, 2021 at 21:08
  • I am using termux (arch linux) and here is my answer : 2>/dev/null ifconfig | grep inet | tail -1 | awk '{print $2}' it will give you exact local ip
    – Khan Saad
    Commented Sep 27, 2022 at 8:25
10

Im extracting my comment to this answer:

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

It bases on @CollinAnderson answer which didn't work in my case.

4
  • This will get you your IP on the default network. But if you have multiple interfaces (e.g. a VPN, maybe a WAN...), and need the local IP address as seen by some other IP on one of those connected networks, simply substitute that other IP address for the 1 in the ip route command... et voilà!
    – Lambart
    Commented May 20, 2021 at 0:30
  • I think this is the most usable answer, only note that this might not work on some systems/versions because of last space char in sed command (src might be last portion in the line). I think it is ok without it: ip route get 1 | sed -nr 's/^.* src ([0-9.]*).*/\1/p'
    – Alek
    Commented Jun 3, 2021 at 1:06
  • can do without a capture group: ip --oneline route get 1 | sed 's/.* src //g;s/ .*//g'
    – Lucas
    Commented Apr 10, 2023 at 16:22
  • @Lucas if it works for you is ok, but it won't work in all distros. Check unix.stackexchange.com/questions/420965/…
    – estani
    Commented Apr 13, 2023 at 13:50
9

Finds an IP address of this computer in a network which is a default gateway (for example excludes all virtual networks, docker bridges) eg. internet gateway, wifi gateway, ethernet

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

Works on Linux.

Test:

➜  ~ 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
1
8

Assuming you need your primary public IP as it seen from the rest of the world, try any of those:

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

I have to add to Collin Andersons answer that this method also takes into account if you have two interfaces and they're both showing as up.

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

I have been working on an application with Raspberry Pi's and needed the IP address that was actually being used not just whether it was up or not. Most of the other answers will return both IP address which isn't necessarily helpful - for my scenario anyway.

1
  • Better use JSON instead: ip -j r g 1 | python3 -c 'import sys,json; print(json.load(sys.stdin)[0]["prefsrc"])' (works for Ansible, too)
    – Tino
    Commented Feb 28 at 10:47
5
ip addr show | grep -E '^\s*inet' | grep -m1 global | awk '{ print $2 }' | sed 's|/.*||'
1
  • I don't know why this one seems to be glossed over.
    – Folaht
    Commented Nov 23, 2021 at 14:46
5

The shortest way to get your local ipv4-address on your linux system:

hostname -I | awk '{print $1}'
2
  • 5
    Bad. The man page tells you specifically not to make any assumptions about the order of the output.
    – hookenz
    Commented Sep 3, 2015 at 2:10
  • Works great for my trivial use cases – I don't care if it is quick and dirty! Great! Commented Apr 18, 2019 at 19:52
4

Primary network interface 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
3

Not sure if this works in all os, try it out.

ifconfig | awk -F"[ :]+" '/inet addr/ && !/127.0/ {print $4}'
3
  • Doesn't work on CentOS 7.0 Commented Feb 3, 2015 at 12:13
  • @BenoitBlanchon Then use this ip route get 1 | awk '{print $NF;exit}'. Should work on most system.
    – Jotne
    Commented Feb 3, 2015 at 12:37
  • Indeed ip route get 1 | awk '{print $NF;exit}' works Commented Feb 3, 2015 at 13:49
3

Another ifconfig variantion that works both on Linux and OSX:

ifconfig | grep "inet " | cut -f2 -d' '
2
  • 1
    one small variation: ifconfig | grep '\<inet\>' | cut -d ' ' -f2 | grep -v '127.0.0.1'
    – jpbochi
    Commented Aug 5, 2016 at 17:35
  • Why do half of these answers not work at all for me? Commented Jun 8, 2020 at 1:39
3

I just utilize Network Interface Names, my custom command is

[[ $(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' 

in my own notebook

[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 ~]$

but if the network interface owns at least one ip, then it will show all ip belong to it

for example

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 Jessie

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 ~]#

It seems like that command ip route get 1 | awk '{print $NF;exit}' provided by link is more accurate, what's more, it more shorter.

2

I went through a lot of links (StackExchange, AskUbuntu, StackOverflow etc) and came to the decision to combine all the best solutions into one shell script.

In my opinion these two QAs are the best of seen:

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

Here is my solution based on some ideas by rsp shared in his repository (https://github.com/rsp/scripts/).

Some of you could say that this script is extremely huge for so simple task but I'd like to make it easy and flexible in usage as much as possible. It supports simple configuration file allowing redefine the default values.

It was successfully tested under Cygwin, MINGW and Linux (Red Hat).

Show internal IP address

myip -i

Show external IP address

myip -e

Source code, also available by the link: https://github.com/ildar-shaimordanov/tea-set/blob/master/home/bin/myip. Example of configuration file is there, next to the main script.

#!/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
2

Works on Mac, Linux and inside Docker Containers:

$ 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}')

Also works on Makefile as:

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}')}

1
  • Mac don't work: hostname --ip-address => hostname: illegal option -- - on macOS Sierra
    – JL Peyret
    Commented Feb 24, 2018 at 22:46
2

There's a node package for everything. It's cross-platform and easy to use.

$ npm install --global internal-ip-cli

$ internal-ip
fe80::1

$ internal-ip --ipv4
192.168.0.3

This is a controversial approach, but using npm for tooling is becoming more popular, like it or not.

1

If you know the network interface (eth0, wlan, tun0 etc):

ifconfig eth0 | grep addr: | awk '{ print $2 }' | cut -d: -f2
1
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
1
  • not working on macOS 10.12.6
    – Antoine F.
    Commented Oct 26, 2017 at 10:32
1
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]*' 
1

For linux, what you need is this command:

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

type this in your shell and you will simply know your ip.

1
  • No. It does not work. Commented Jul 26, 2017 at 19:29
1

This is easier to read: ifconfig | grep 'inet addr:' |/usr/bin/awk '{print $2}' | tr -d addr:

1
  • not working on macOS 10.12.6
    – Antoine F.
    Commented Oct 26, 2017 at 10:31
1

If you have npm and node installed : npm install -g ip && node -e "const ip = require('ip'); console.log(ip.address())"

Not the answer you're looking for? Browse other questions tagged or ask your own question.