50

I want to make big script on my Debian 7.3 ( something like translated and much more new user friendly enviroment ). I have a problem. I want to use only some of the informations that commands give me. For example my ifconfig looks like:

eth0      Link encap:Ethernet  HWaddr 08:00:27:a3:e3:b0  
          inet addr:192.168.1.103  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fea3:e3b0/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1904 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2002 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:1309425 (1.2 MiB)  T

I want to display only the IP address in line: echo "Your IP address is: (IP_ADDRESS )". Is there any command that allow me to do such a thing, to search in stream for informations I want to get?. I know about grep and sed but I am not really good with them.

Edit: Firstly to say thank you for helping me with this problem, now I know much more. Secondly to say project is in progress. If anyone would be interested in it just pm me.

Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174
user3232381
  • 531
  • 1
  • 4
  • 6
  • 1
    Also look at the documentation for pipes in man bash. – Alex Brown Jan 24 '14 at 15:19
  • 3
    There is a fundamental problem with what your trying to do: machines can often have multiple IP addresses (one for wired connection, one for wireless connection, one for virtual machine connection, etc.). You'll need to think about which one you want. – James Kingsbery Jan 24 '14 at 15:22
  • @JamesKingsbery I didn't take this into consideration. I will think about it later. Thank you for showing me next problem. PS: Thank you for sending me man grep reference. It really helped. – user3232381 Jan 24 '14 at 15:28

15 Answers15

105

If the goal is to find the IP address connected in direction of internet, then this should be a good solution.

Edit 2021: Added "sed" and "grep" versions and new "awk" versions (some are gnu)


To find what IP adders is used connected to internet, we can use the ip route command. With newer version of Linux you get more information with a typical output some like this:

ip route get 8.8.8.8
8.8.8.8 via 10.36.15.1 dev ens160 src 10.36.15.150 uid 1002
    cache

so to get IP you need to find the IP after src, using awk, sed or grep

ip route get 8.8.8.8 | awk -F"src " 'NR==1{split($2,a," ");print a[1]}'
ip route get 8.8.8.8 | awk 'match($0,/src (\S*)/,a)&&$0=a[1]'
ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++)if($i~/src/)$0=$(i+1)}NR==1'

ip route get 8.8.8.8 | sed -E 's/.*src (\S+) .*/\1/;t;d'
ip route get 8.8.8.8 | sed 's/.*src \([^ ]*\).*/\1/;t;d'
ip route get 8.8.8.8 | sed  -nE '1{s/.*?src (\S+) .*/\1/;p}'

ip route get 8.8.8.8 | grep -oP 'src \K[^ ]+'
10.36.15.150

and if you like the interface name using awk, sed or grep

ip route get 8.8.8.8 | awk -F"dev " 'NR==1{split($2,a," ");print a[1]}'
ip route get 8.8.8.8 | awk 'match($0,/dev (\S*)/,a)&&$0=a[1]'
ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++)if($i~/dev/)$0=$(i+1)}NR==1'

ip route get 8.8.8.8 | sed -E 's/.*?dev (\S+) .*/\1/;t;d'
ip route get 8.8.8.8 | sed 's/.*dev \([^ ]*\).*/\1/;t;d'
ip route get 8.8.8.8 | sed  -nE '1{s/.*?dev (\S+) .*/\1/;p}'

ip route get 8.8.8.8 | grep -oP 'dev \K[^ ]+'
ens192

ip route does not open any connection out, it just shows the route needed to get to 8.8.8.8. 8.8.8.8 is Google's DNS.

If you like to store this into a variable, do:

my_ip=$(ip route get 8.8.8.8 | awk -F"src " 'NR==1{split($2,a," ");print a[1]}')

my_interface=$(ip route get 8.8.8.8 | awk -F"dev " 'NR==1{split($2,a," ");print a[1]}')

Why other solution may fail:

ifconfig eth0

  • If the interface you have has another name (eno1, wifi, venet0 etc)
  • If you have more than one interface
  • IP connecting direction is not the first in a list of more than one IF

Hostname -I

  • May get only the 127.0.1.1
  • Does not work on all systems.
  • Give all IP not only the one connected to internet. -I, --all-ip-addresses all addresses for the host
Jotne
  • 40,548
  • 12
  • 51
  • 55
  • 3
    This is the best soluion as if does not depend on knowing the interface name a priori. If the interface name changes, the script will not break. Also, note that if you have different interfaces for different subnets/WAN/etc, you can pick the right IP by just replacing 8.8.8.8 (just use an IPthat you know is on the network that you want). – Jay Apr 27 '14 at 13:03
  • @Jay You are correct. I am working with multiple vendors of `VPS` server, and there interface are often not just `eth0` but can be like this `venet0` and many other. – Jotne Apr 27 '14 at 15:43
  • +1 Very elegant solution. Too bad it's not available on OS X as well. Even with the iproute2mac package installed the "src" data parsed from the output of the command isn't present. I would be curious to know what "ip route get" might be replaced with in OS X networking commands that could be used instead if anyone knows. – Mark Edington Nov 01 '15 at 20:49
  • This doesn't actually work if you don't have a route to 8.8.8.8, so while it's a 99% solution, it's not 100%. 100% solutions are platform specific, and generally require that you know your interface name. – Nick Bastin Feb 03 '17 at 06:58
  • @NickBastin You are wrong. This solution is to find your interface that is used to reach internet. If you do not have internet, then you do no need this. You do not need to reach this IP, it will find correct interface. – Jotne Sep 27 '17 at 17:31
  • @Jotne: The OP question was how to find an interface (or host, presumptively) IP address. This is not the proper way to do that. The question makes no assertion that the interface in question is connected to the internet. – Nick Bastin Oct 01 '17 at 20:01
  • @NickBastin That is correct, but from the data he posted, and from that he accepted an answer that respond the same way I do, you can assume that he is looking for the IP of the outside interface. Also other assume the same, sine my answer has 65 up-vote. My post is also a comment to not use: ifconfig eth0. What you make out of it is up to you :) – Jotne Oct 02 '17 at 19:44
  • @Jotne: the point is that this answer may not help the *next* person, because the answer does not match the question that was actually asked, and someone with the same question will find this upvoted answer. *I* upvoted this answer, although I am now considering removing that vote, since it seems clear that you don't want to add any qualification that this only works if this is an internet-facing interface. – Nick Bastin Oct 16 '17 at 15:19
  • @NickBastin rewritten my answer to clarify what it answer. – Jotne Dec 04 '17 at 22:19
  • 1
    Newer iproute2 has an option to output JSON, which is more reliable and simpler for parsing. Here is an example: `ip --json route get 8.8.8.8 | jq -r '.[].prefsrc'`. Need to install an extra program, though. – Chih-Hsuan Yen May 01 '21 at 09:29
  • @Chih-HsuanYen `Need to install an extra program` not true. My ubuntu did ask for `apt install jq`. And when I installed `jq`, I do get this error `parse error: Invalid numeric literal at line 1, column 8` .Both `ip route` and `awk` are standard on most linux – Jotne May 17 '21 at 18:37
  • @Jotne What's the output of `ip --json route get 8.8.8.8` on your machine? – Chih-Hsuan Yen May 18 '21 at 16:06
  • @Chih-HsuanYen I do get the same output on all server as without `--json`. No different. – Jotne Jun 07 '21 at 19:07
  • @Jotne That sounds like a bug in older iproute2. That bug is fixed in iproute2 5.0 (https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/commit/?id=a0a639d9c002d957ce9d5547c806919cbffa3834). – Chih-Hsuan Yen Jun 08 '21 at 07:10
  • This is maybe too much of a tangent, but what if you have multiple interfaces that can get to 8.8.8.8 (i.e. ethernet and wifi both have internet connectivity). Any way to specifically get one over the other? On my machine it defaults to the ethernet address when I'm actually interested in getting the wifi one. – topher217 Sep 13 '21 at 07:06
  • @topher217 Have no good answer for you. I guess it takes the first that answer. – Jotne Oct 06 '21 at 18:10
43

To just get your IP address:

echo `ifconfig eth0 2>/dev/null|awk '/inet addr:/ {print $2}'|sed 's/addr://'`

This will give you the IP address of eth0.

Edit: Due to name changes of interfaces in recent versions of Ubuntu, this doesn't work anymore. Instead, you could just use this:

hostname --all-ip-addresses or hostname -I, which does the same thing (gives you ALL IP addresses of the host).

Marco Hegenberg
  • 612
  • 7
  • 5
  • 6
    The `echo` is doing nothing. Also you never need `sed` with `awk` since awk can do anything sed can do. – Ed Morton Jan 24 '14 at 17:48
  • 7
    You should not use back tics its old, use parentheses `$(code)`. It will also fail if IF is not eth0. This could be written more like this: `ifconfig eth0 | awk -F"[: ]+" '/inet addr:/ {print $4}'` – Jotne Apr 19 '14 at 17:59
  • 6
    Consider using `hostname -I`. per @DanilaV.'s comment. nowadays the naming of NICs may not be ethX, many flavors of linux have started using **em** to prefix interfaces. – icdevppl Jun 10 '15 at 20:06
  • 1
    In Ubuntu >= `15.x` they have renamed interface from `eth0` to `eno1`, so there this script does not work at all – Jotne Apr 28 '16 at 06:31
  • 1
    Thank you for your remarks. I added "hostname --all-ip-addresses" to the solution, which is the same as hostname -I (thank you icdevppl!). – Marco Hegenberg Nov 29 '16 at 09:11
  • 'grep-awk-sed-ing' is not future-proof. This trick no longer works in newer Linux versions, as they output: `inet 10.50.0.8 netmask 255.255.0.0 broadcast 10.50.255.255` – Halfgaar Feb 19 '18 at 20:31
  • @MarcoHegenberg `hostname -I` give you all interface IP, if the goal is to find IP that is used to connect to internet, this will not give that. – Jotne Mar 05 '21 at 07:38
39

If you want to get a space separated list of your IPs, you can use the hostname command with the --all-ip-addresses (short -I) flag

hostname -I

as described here: Putting IP Address into bash variable. Is there a better way?

Community
  • 1
  • 1
user000001
  • 32,226
  • 12
  • 81
  • 108
  • Command that you mention here is really good but my project is still in progress and i am not 100% what i will need. – user3232381 Jan 24 '14 at 20:19
  • 1
    Will not always get one single IP. On my VPS server I get this output `127.0.0.2 143.127.52.130 2a00:dee0:ed3:83:245:70:fc12:d196`, so then I need to add some filters. – Jotne Nov 10 '14 at 11:48
  • 2
    @Jotne If you have multiple IPs you can cut the output to the one you want (e.g. the first one) like this: `hostname -I | cut -f1 -d' '`, although I agree that using the `ip` tool is better if the order of the interfaces can change – user000001 Nov 10 '14 at 11:50
  • 2
    love it - on the assumption that there is only 1 address this is perfect!. Here is another rough and ready way of getting it via "ip" ip addr | grep "scope global" | sed 's:^[^0-9]*::' | sed 's:/.*$::' – Pancho Jun 01 '15 at 08:26
  • 1
    hostname doesn't have -I on OS X, so this is good for Linux only. – Robert P. Goldman Feb 18 '16 at 21:08
  • Is not a OS X problem. the problem is that you a reading a 5 year old answer – harogaston Nov 20 '19 at 13:41
16
ip -4 addr show eth0 | grep -oP "(?<=inet ).*(?=/)"
Andy
  • 17,423
  • 9
  • 52
  • 69
John
  • 169
  • 1
  • 2
9

May be not for all cases (especially if you have several NIC's), this will help:

hostname -I | awk '{ print $1 }'
Pavel
  • 424
  • 3
  • 12
6
ip route get 8.8.8.8| grep src| sed 's/.*src \(.* \)/\1/g'|cut -f1 -d ' '
fastrizwaan
  • 190
  • 1
  • 3
  • 2
    Thank you for posting an answer to this question! Code-only answers are discouraged on Stack Overflow, because it can be difficult for the original poster (or future readers) to understand the logic behind them. Please, edit your question and include an explanation of your code so that others can benefit from your answer. Thanks! – Maximillian Laumeister Sep 18 '15 at 02:07
4

Take your pick:

$ cat file
eth0      Link encap:Ethernet  HWaddr 08:00:27:a3:e3:b0
          inet addr:192.168.1.103  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::a00:27ff:fea3:e3b0/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1904 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2002 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1309425 (1.2 MiB)  T

$ awk 'sub(/inet addr:/,""){print $1}' file
192.168.1.103

$ awk -F'[ :]+' '/inet addr/{print $4}' file
192.168.1.103
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
4
  /sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}'
Tharanga Abeyseela
  • 3,255
  • 4
  • 33
  • 45
4

In my opinion the simplest and most elegant way to achieve what you need is this:

ip route get 8.8.8.8 | tr -s ' ' | cut -d' ' -f7

ip route get [host] - gives you the gateway used to reach a remote host e.g.:

8.8.8.8 via 192.168.0.1 dev enp0s3  src 192.168.0.109

tr -s ' ' - removes any extra spaces, now you have uniformity e.g.:

8.8.8.8 via 192.168.0.1 dev enp0s3 src 192.168.0.109

cut -d' ' -f7 - truncates the string into ' 'space separated fields, then selects the field #7 from it e.g.:

192.168.0.109
leonardo
  • 1,686
  • 15
  • 15
3

Just a note, since I just spent some time trouble-shooting a botched upgrade on a server. Turned out, that (years ago) I had implemented a test to see if dynamically added interfaces (e.g. eth0:1) were present, and if so, I would bind certain proggis to the 'main' IP on eth0. Basically it was a variation on the 'ifconfig|grep...|sed... ' solution (plus checking for 'eth0:' presence).
The upgrade brought new net-tools, and with it the output has changed slightly:

old ifconfig:

eth0      Link encap:Ethernet  HWaddr 42:01:0A:F0:B0:1D
          inet addr:10.240.176.29  Bcast:10.240.176.29  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1460  Metric:1
          ...<SNIP>

whereas the new version will display this:

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1460
      inet 10.240.212.165  netmask 255.255.255.255  broadcast 10.240.212.165
      ...<SNIP>

rendering the hunt for 'eth0:' as well as 'inet addr:' search busted (never mind interfaces called 'em0','br0' or 'wlan0'...). Sure you could check for 'inet ' (or 'inet6'), and make the addr: part optional, but looking closer, you'll see that more or less everything has changed, 'Mask' is now 'netmask',...

The 'ip route ...' suggestion's pretty nifty - so maybe:

_MyIP="$( ip route get 8.8.8.8 | awk 'NR==1 {print $NF}' )"
if [ "A$_MyIP" == "A" ]
then
    _MyIPs="$( hostname -I )"
    for _MyIP in "$_MyIPs"
    do
        echo "Found IP: \"$_MyIP\""
    done
else
    echo "Found IP: $_MyIP"
fi

Well, something of that sort anyway. Since all proposed solutions seem to have circumstances where they fail, check for possible edge cases - no eth, multiple eth's & lo's, when would 'hostname -i' fail,... and then decide on best solution, check it worked, otherwise 2nd best.

Cheers 'n' beers!

Kevin
  • 59
  • 3
1

A slight modification to one of the previous ip route ... solutions, which eliminates the need for a grep:

ip route get 8.8.8.8 | sed -n 's|^.*src \(.*\)$|\1|gp'
Deacon
  • 3,615
  • 2
  • 31
  • 52
  • My Ubuntu 20.04 system has stuff after the IP, so this elegant solution doesn't quite isolate just the IP. Sample output looks like this: 192.168.9.9 uid 0 – Ian D. Allen Sep 14 '22 at 04:58
1

If You want to use only sed to extract IP address:

ifconfig eth0 2>/dev/null sed -n 's/.*[[:space:]]\([[:digit:]][[:digit:]]*\.[[:digit:]][[:digit:]]*\.[[:digit:]][[:digit:]]*\.[[:digit:]][[:digit:]]*\).*/\1/p'
baziorek
  • 2,502
  • 2
  • 29
  • 43
1

A slight modification to one of the previous ip route ... solutions that uses only ip and sed and properly isolates just the IPv4 IP:

ip -4 route get 1.1.1.1 | sed -n 's/^.*src \([0-9.]*\).*$/\1/p'
Ian D. Allen
  • 201
  • 2
  • 7
0
awk '/inet addr:/{gsub(/^.{5}/,"",$2); print $2}' file
192.168.1.103
Claes Wikner
  • 1,457
  • 1
  • 9
  • 8
0

Assuming you've installed jq, and your interface name is eth0, I found this to be the cleanest of many, many things I tried:

ip -4 -br -j addr show dev eth0 | jq -r '.[0].addr_info[0].local'
depperm
  • 10,606
  • 4
  • 43
  • 67
whoasked
  • 390
  • 2
  • 15