For when you have many network interfaces Link to heading
The short version: Link to heading
ip addr show $(ip route | awk '/default/ { print $5 }') | grep "inet" | head -n 1 | awk '/inet/ {print $2}' | cut -d'/' -f1
- We use
ip routeandawkto determine the name of our default network interface - We use
ip addrto get the IP details for that interface - We grep for only the line(s) that indicate “inet”
- We then make sure we are only dealing with one line via the
headcommand. There should only be a single “inet” line to begin with, but it is possible there could be more than one. - We use
awkto extract the IP address - We use
cutto strip off the subnet information if it is present
This is a little verbose, but works very well for my use case. This can be done in a more concise manner with a little effort. Adopt this, or use another technique to suit your needs.
My Use Case Link to heading
Note, I’m going to gloss over some details as being irrelevant to the conversation. The goal here is to focus on finding the IP address of the host workstation from a command line script (Bash in this case), when more than one network interface may be present and hard coding an interface name is not the right answer.
I had a docker container running on my Linux workstation that provided a web service via an exposed port. I could just navigate to http://localhost:51234 to access that service. The interesting part occurred when I needed a different unrelated docker container to access that same service. In this case I did not have a common Docker network configuration I could lean on. I needed to just do a typical HTTP request, but “localhost” from INSIDE that container meant the container — not my host computer. The fix here is to just use the IP address of the host, BUT… The script I was creating is expected to run on multiple developer’s boxes each with their own local version of the web service, and their own IP addresses. So I couldn’t just hard code my IP. Asking the dev’s to edit a config was not convenient either (short lease times on the DHCP address, different skills of the devs, etc.). So I needed a way to determine the IP address of the host computer from the Bash script that was launching the processes.
So I hacked it.
I started with the typical ip addr. This lists the IPv4 and IPv6 addresses for all the network interfaces. If I assume my default interface is eth0 I could narrow this down with
ip addr show eth0
But, there is nothing special about the list that indicates which interface is the “default”. The default is an “inferred” piece of knowledge based on how we setup the computer, what hardware was available, etc. So I can’t use eth0 or wlan0, because there is no guarantee the “default” interface would be named the same on all the host computers.
The answer for me was to also make use of ip route. This lists the routing tables for the workstation. The important part there is the line that indicates “default via”. This is our default interface. Combining that we can then do
ip route | awk '/default/ {print $5}'
This gives us the NAME of the default interface. The ip route gives us our list of routing entries, and the awk command finds the one with the phrase “default”, then returns the 5th field from that line (space delimited). Interestingly, if you need the IP address of your default gateway, you can just change that to $3 instead of $5.
Combining that then gives us
ip addr show $(ip route | awk '/default/ {print $5}')
and this returns the IP information for our default device. To trim that output down even more we can use awk, grep, head, and cut to isolate the “inet” line(s). and extract ONLY the desired IP address. I’ve described what each piece does up above, under the “short version”.
I use it in my script like this:
MYIP=$(ip addr show $(ip route | awk '/default/ { print $5 }') | grep "inet" | head -n 1 | awk '/inet/ {print $2}' | cut -d'/' -f1)
If I then “echo $MYIP” I get something like “192.168.1.55”. And this is the value I can then pass into my secondary Docker container (I used the --env flag with the docker run command to do so). My running container can then access “http://192.168.1.55:51234” and get the results it expected, assuming everything else is running properly.
There are tons of answers on the Internet that show how to get your IP address. In my case, most of those were too simplistic or still relied on some inferred knowledge.
Thanks to the gang on the #debian IRC channel for their help in getting to this solution!