437

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.

sorin
  • 161,544
  • 178
  • 535
  • 806
  • 2
    Do you just want your machine local network IP? i.e 192.168.0.12 – Chris Seymour Nov 10 '12 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 Nov 10 '12 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 Nov 10 '12 at 17:06
  • 10
    Try `curl -4 ifconfig.co` . It will answer with your external IP4 address. – asmaier Aug 06 '19 at 09:34
  • How is this off-topic? – Ganesh Kathiresan Jul 20 '20 at 09:12
  • I've just used `curl ifconfig.me` and it worked fine. – Tiago Martins Peres Jan 20 '21 at 15:06
  • `bash: ifconfig: command not found` --> the command is deprecated, see [ifconfig and locate command not found, `bash: ifconfig: command not found`](https://unix.stackexchange.com/questions/631542/ifconfig-and-locate-command-not-found) on Unix & Linux Stack Exchange where the question belongs. – questionto42 Jul 22 '22 at 21:19
  • `2>/dev/null ifconfig | grep inet | tail -1 | awk '{print $2}'` I think this is the answer you are looking for. – Khan Saad Sep 27 '22 at 08:26

31 Answers31

581

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.

Artem Russakovskii
  • 21,516
  • 18
  • 92
  • 115
Chris Seymour
  • 83,387
  • 30
  • 160
  • 202
  • 5
    Note also that in OSX, sed uses the `-E` option for Extended RE, not the GNU-style `-r` option. – ghoti Nov 10 '12 at 19:51
  • @ghoti Linux supports both but only documents `-r` is the converse true for OSX? – Chris Seymour Nov 10 '12 at 19:55
  • 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 Nov 10 '12 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` – Chris Seymour Nov 10 '12 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 https://gist.github.com/ssbarnea/31b9dcb0f8fd528b958c -- it also returns the vnic ones that are active but used by paralles. – sorin Aug 28 '13 at 11:16
  • @sorin like I said in my answer 10 months ago if you want to filter by interface then do `ifconfig en1 | sed ...` – Chris Seymour Aug 28 '13 at 12:03
  • Can this support ipv6 addresses? – CMCDragonkai Jun 02 '14 at 04:29
  • 1
    Note about `hostname`: `-I` is a shortcut for `--all-ip-addresses` which displays all configured network addresses on all network interfaces, each separated by a space. It excludes the loopback interface (127.0.0.0/8) and IPv6 link-local addresses. It does not depend on name resolution. The output order is arbitrary. Older versions of the command (at least 1.1) do not have this option, but do have one for `-i`, a shortcut for `--ip-address` which displays all network addresses for the *resolved* host name, and as such should be avoided per the manual (for newer versions with `-I`). – Synexis Dec 14 '14 at 01:47
  • Slight modification for when you know some of the address. This one only returns addresses in the range `10.0.0.0/16`. `ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(10\.0\.[0-9]*\.[0-9]*).*/\2/p'`. – aembke Jul 18 '15 at 20:06
  • 20
    OSX: ipconfig getifaddr en0 – parleer Nov 16 '15 at 05:12
  • This doesn't work in Linux distribution with `LANG` different to "en" or "en_*", because `ifconfig` returns the `inet` label translated to the user language. The best way to do this regardless of the the *nix system (Linux, OSX, ...) and regardless of the user language is here: http://stackoverflow.com/questions/23934425/parse-ifconfig-to-get-only-my-ip-address-using-bash/37212665#37212665 – Mariano Ruiz Aug 04 '16 at 16:37
  • you should probably exclude other private ips, as 172.17. this are widely used for docker container traffic redirection. – useless Sep 05 '16 at 13:46
  • This doesn't answer the question, it just provides a list of all IPs, not the primary (default route) one. – Endareth Mar 24 '17 at 03:03
  • So what about an ipv6-only host? – Martijn Pieters Apr 09 '17 at 17:43
  • 1
    **THIS IS DANGEROUS**. It fails to avoid the internal IP addresses and in this day of Dockers and VPNs and stuff there is often many of them. If you know the interface, then fine, but this does not show how to find it. – Jan Hudec Mar 21 '18 at 09:19
  • Replace `ifconfig` with `ip` for Arch Linux – Mattwmaster58 May 22 '18 at 04:01
  • You can also use `hostname -I` in Linux server – Mr T Nov 27 '19 at 10:27
  • 1
    This returns multiple ip address if its run inside a google inside like `172.18.0.1 172.17.0.1 ` – alper Jul 25 '21 at 15:29
  • This answer is ***deprecated***!! – F. Hauri - Give Up GitHub May 22 '23 at 11:37
297

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
Rob Bednark
  • 25,981
  • 23
  • 80
  • 125
Collin Anderson
  • 14,787
  • 6
  • 68
  • 57
  • 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. – Adam Ryczkowski Sep 23 '14 at 23:27
  • `ip -4 route get 1 | head -1 | cut -d' ' -f8 | tr -d '\n'` (if you want IPv4 address and truncate to avoid empty spaces) – luchaninov Jul 10 '15 at 10:44
  • 3
    Note that none of these work on OS X. – pmdarrow Jun 16 '16 at 16:07
  • 2
    Note that `ip route get 8.8.8.8 | head -1 | cut -d' ' -f8` doesn't work for local network IPs, only for remote ones as the output of `ip route get` is different then (the `via 192.168.1.1` part is missing). You'd need to change `-f8` to `-f6` then. Or simply use the `awk` solution which works reliable in all of those cases for me. – mozzbozz Jan 30 '17 at 14:35
  • More detailed response that uses the same `ip route get 8.8.8.8` technique, from the related post: http://stackoverflow.com/a/21336679/6862601 – codeforester Feb 02 '17 at 19:47
  • The advantage of this method is, at least on my Linux box, that it can be run by a normal user, while `ifconfig` requires root. – Christian Herenz Apr 18 '17 at 16:01
  • 20
    For me `ip route get 1 | awk '{print $(NF-2);exit}'` works as I get uid appended to the outptut – Hritik Sep 29 '17 at 08: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 Mar 21 '18 at 09:17
  • 25
    it didn't work for me but it was closed enough: `ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'` – estani Jul 24 '18 at 08:16
  • 3
    The solution of @estani works for the new `ip` output (which appends "uid xxxx") and for the old `ip` output. – scottkosty Aug 05 '18 at 21:28
  • @scottkosty thanks for testing, I extract it to an answer, cause here won't be found. – estani Aug 09 '18 at 13:00
  • 6
    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 Nov 16 '18 at 17:27
  • 1
    `hostname -I | cut -d' ' -f1` works on 16.04 _and_ 18.04 – Duncan Calvert Feb 14 '19 at 20:58
  • I tried on OS X 10.13.6 (macOS High Sierra) and these two work fine: `ip route get 1 | awk '{print $NF;exit}'` and `ip route get 8.8.8.8 | head -1 | cut -d' ' -f8` The first one needs the `$` back-slash escaped as bash alias; the second does not need that. – Jeroen Wiert Pluimers Feb 15 '19 at 22:41
  • 2
    I think `ip route get 1 | awk '{gsub("^.*src ",""); print $1; exit}'` is better - there are too many different variants of ip route that have different things on that line. This looks for the IP that goes with "src" and prints it. – rfay May 29 '19 at 17:16
  • ip route get 1 | sed -e 's/ /\n/g' | grep -A1 src | tail -n 1 – aep Mar 20 '20 at 08:46
  • ip route get 1 | awk '{print $NF;exit}' returns 1000 for me is that correct ? I actually expected 192.168.178.23 – sqp_125 Nov 01 '20 at 06:51
  • As with similar answers, if you have multiple interfaces (e.g. a VPN) and need the local IP address _as seen by any other arbitrary IP_, simply substitute that other IP address for `1`/`8.8.8.8`. – Lambart May 20 '21 at 00:06
  • @sqp_125 As @estani also noted, the first version doesn't work for me because of the `uid` added to the output. It just returns your uid (1000 in your case). See estani's answer here: https://stackoverflow.com/a/51767744/1339923 – Lambart May 20 '21 at 00:09
  • 1
    `ip route get 1 | sed -nr 's/^.* src ([0-9.]+)( .*|)$/\1/p'` - this will work with and without uid suffix – Alek Nov 04 '21 at 18:35
  • Only the ``` less reliable way``` worked for me – Magno C Aug 20 '23 at 20:14
259

For linux machines (not OS X) :

hostname --ip-address
ACyclic
  • 5,904
  • 6
  • 26
  • 28
  • 12
    That only works if the name is in DNS. If not, you get the message "hostname: Name or service not known." – Vebjorn Ljosa Nov 10 '13 at 05:21
  • 46
    `hostname -i` is the equivalent short form – Paul Evans May 13 '14 at 13:45
  • 86
    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 Jun 12 '14 at 16:33
  • 1
    It doesn't work on Linux either, at least not with `hostname` in GNU Coreutils version 8.26. – ack Mar 10 '17 at 05:33
  • 8
    On my machine, `hostname -i` gives only the local IP, while `hostname -I` gives all the other IPs – Alexis Paques Jul 21 '17 at 06:42
  • 2
    This returned 127.0.0.1 on my machine – mitiko Aug 04 '17 at 18:39
  • 1
    **THIS IS DANGEROUS**. It fails to avoid the internal IP addresses and in this day of Dockers and VPNs and stuff there is often many of them. If you know the interface, then fine, but this does not show how to find it. – Jan Hudec Mar 21 '18 at 09:19
  • this just shows 127.0.0.1 for me on Redhat server, maybe depends on your /etc/ssh/sshd_config settings? – m1m1k Apr 09 '18 at 15:28
  • if you have ipv6 enabled, it will return on the same line both ipv4 and ipv6 address. – Giovanni Toraldo Jan 21 '19 at 12:44
  • The [`hostname` manpage](https://manpages.debian.org/hostname/hostname.1.en.html) (on Debian) for `-i, --ip-address` says "`Avoid using this option; use hostname --all-ip-addresses instead`" – Boris Verkhovskiy Apr 26 '20 at 14:42
99

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.
HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
giosh94mhz
  • 2,908
  • 14
  • 25
93

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.

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
48

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

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
    [ "$lne" = "inet" ] && [ "$lip" = "$ip" ] && mask=$lmask
done < <(ip a s dev $iface)

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

Then if you want to see your mask as an 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

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
F. Hauri - Give Up GitHub
  • 64,122
  • 17
  • 116
  • 137
  • 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. :-) – F. Hauri - Give Up GitHub Nov 10 '12 at 15:10
  • 1
    @sorin try this with `time` to select which you would use so long... – F. Hauri - Give Up GitHub Nov 10 '12 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 Mar 17 '15 at 04:58
  • This does not show the public ip address , like ```curl ifconfig.me``` does – alper Jul 25 '21 at 15:32
  • @alper this is not the scope of request... And `ifconfig.me` is just another *what-is-my-ip* provider. – F. Hauri - Give Up GitHub Jul 25 '21 at 16:12
  • Your solution does not return the IP address that users can connect into the machine using `ssh`. Most of the other answers does since its the scope of the request. – alper Jul 25 '21 at 18:07
  • @alper My solution return my ip used to adress *router*. Public IP and routing from public network to my private ip is a *router* concern. All hosts on my private network could reach my host by IP returned by my solution. And If I want to connect from public network, THIS is THE IP I have to configure into the *router* for this. – F. Hauri - Give Up GitHub Jul 26 '21 at 07:16
  • Thanks for the update its more clear now. I am just confused to visualize how the routing process is done, is it done from the modem's interface? I have tried your solution inside a google instance, since I don't have access to their routers I need the machine's public IP inorder for me to ssh into it. For my VMs using VMware Workstation `Bridged: Connected directly to the pyhsical network` check, I am required to its public IP as well. I did not understand how did you configured the router, have you done port forwarding for this? – alper Jul 26 '21 at 08:45
  • @alper Yes, I was speaking about *private network*. About google cloud, I don't know, but if you can reach your *instance*, you should be able to access it from a *web browser* **and** from a *ssh client*!? – F. Hauri - Give Up GitHub Jul 26 '21 at 10:05
  • @F.Hauri Yes sir related to google instance, I can access them from a browser and from a ssh client using the IP address returned by `curl ifconfig.me`. – alper Jul 26 '21 at 11:11
29

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

hostname  -i

or

hostname -I
Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
user3173508
  • 339
  • 3
  • 2
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
Sathish
  • 3,477
  • 3
  • 26
  • 28
  • This assumes eth0, which is not current naming strategy and never was guaranteed to be the primary interface. – rfay May 29 '19 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 Dec 20 '19 at 07: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}'
Shahriar
  • 13,460
  • 8
  • 78
  • 95
Kjeld Flarup
  • 1,471
  • 10
  • 15
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

Colin Fletcher
  • 157
  • 1
  • 2
  • 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 Mar 24 '17 at 03:08
13
ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}'
hqt
  • 29,632
  • 51
  • 171
  • 250
Faizan Noor
  • 846
  • 10
  • 11
  • 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}'"` – Sam Houston Mar 10 '19 at 10:44
  • Right. But the question initially was about the command. So I just posted relevantly. Cheers! – Faizan Noor Mar 11 '19 at 11:04
  • 1
    Don't understand why this answer has less likes. Simple & working!!! – Oomph Fortuity Apr 14 '21 at 03:08
  • Purely with awk, this would be: `ifconfig | awk '/inet / {if($2=="127.0.0.1") {next}; print $2}'` – mike Aug 25 '21 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 Sep 27 '22 at 08: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.

estani
  • 24,254
  • 2
  • 93
  • 76
  • 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 May 20 '21 at 00: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 Jun 03 '21 at 01:06
  • can do without a capture group: `ip --oneline route get 1 | sed 's/.* src //g;s/ .*//g'` – Lucas Apr 10 '23 at 16:22
  • @Lucas if it works for you is ok, but it won't work in all distros. Check https://unix.stackexchange.com/questions/420965/get-local-ip-address-from-ip-route-cross-platform – estani Apr 13 '23 at 13:50
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
Putnik
  • 5,925
  • 7
  • 38
  • 58
8

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
  • Nice! [Taco Bell programming](http://widgetsandshit.com/teddziuba/2010/10/taco-bell-programming.html) at it's best -- thanks for this. – Stevie Howard Mar 26 '19 at 02:07
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.

c7borg
  • 339
  • 3
  • 9
5
ip addr show | grep -E '^\s*inet' | grep -m1 global | awk '{ print $2 }' | sed 's|/.*||'
Gottlieb Notschnabel
  • 9,408
  • 18
  • 74
  • 116
rbolante
  • 53
  • 1
  • 2
5

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

hostname -I | awk '{print $1}'
Gottlieb Notschnabel
  • 9,408
  • 18
  • 74
  • 116
harry
  • 83
  • 1
  • 1
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
kaspars
  • 41
  • 1
  • 1
3

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

ifconfig | awk -F"[ :]+" '/inet addr/ && !/127.0/ {print $4}'
Jotne
  • 40,548
  • 12
  • 51
  • 55
3

Another ifconfig variantion that works both on Linux and OSX:

ifconfig | grep "inet " | cut -f2 -d' '
ccpizza
  • 28,968
  • 18
  • 162
  • 169
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.

Community
  • 1
  • 1
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
Community
  • 1
  • 1
jsxt
  • 1,097
  • 11
  • 28
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}')}

peleteiro
  • 338
  • 2
  • 5
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.

Dennis
  • 56,821
  • 26
  • 143
  • 139
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
Gottlieb Notschnabel
  • 9,408
  • 18
  • 74
  • 116
1

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

ifconfig eth0 | grep addr: | awk '{ print $2 }' | cut -d: -f2
droidgren
  • 6,898
  • 8
  • 31
  • 27
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]*' 
AlanG
  • 11
  • 1
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.

Statham
  • 4,000
  • 2
  • 32
  • 45
1

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

Cory Thorson
  • 97
  • 1
  • 1
1

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

Antoine F.
  • 393
  • 6
  • 16
0

On a Mac, consider the following:

scutil --nwi | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
Chris Seymour
  • 83,387
  • 30
  • 160
  • 202
cl0kc
  • 11