Extracting specific nmap output in bash - bash

I'm getting following nmap output from a scan:
PORT STATE SERVICE
113/tcp closed ident
443/tcp open https
5060/tcp open sip
I want to extract only open ports and save them into a variable while my script progress is below:
#!/bin/bash
echo Please enter your IP/domain address for nmap vulnerability scanning:
read IP
echo Your results against $ip will be output in sometime
nmap -sS -oG output.txt $ip

Grep them
nmap -sS -oG output.txt $ip | grep open
To store in var
open_ports=$(nmap -sS -oG output.txt $ip | grep open)
open_ports=${open_ports//[^0-9]/ } # remove text
Convert to an array
open_ports_arr=( $open_ports )

Here is how you can filter and extract open ports using awk and read the results into a bash array:
#!/usr/bin/env bash
# Read prompt ip address
read \
-p 'Please enter your IP/domain address for nmap vulnerability scanning: ' \
-r ip
# Print format info to user
printf 'Your results against %s will be output in sometime.\n' "$ip"
# Read the output of the nmap | awk commands into the ports array
IFS=$'\n' read -r -d '' -a ports < <(
# Pipe the result of nmap to awk for processing
nmap -sS -oG output.txt "$ip" |
awk -F'/' '
/[[:space:]]+open[[:space:]]+/{
p[$1]++
}
END{
for (k in p)
print k
}'
)
# If the resulting pors array is not empty iterate print format its content
if [ ${#ports[#]} -gt 0 ]; then
printf 'List of open ports on host IP: %s\n' "$ip"
for p in "${ports[#]}"; do
printf '%d\n' "$p"
done
fi

Related

I am not able to Ping IPs from my indexed array but works with an associative array

I am trying to iterate IPs which are read from a csv to an array as a kind of monitoring solution. I have the ips in a indexed array and want to pass the ips to the ping command but its not working.
#!/bin/bash
datei=hosts.csv
length=$(cat $datei | wc -l)
for (( i=1; i<=$length; i++ ))
do
ips[$i]=$(cut -d ';' -f2 $datei | awk 'NR=='$i'')
hosts[$i]=$(cut -d ';' -f1 $datei | awk 'NR=='$i'')
done
servers=( "1.1.1.1" "8.8.4.4" "8.8.8.8" "4.4.4.4")
for i in ${ips[#]} #Here i change the array i want to iterate
do
echo $i
ping -c 1 $i > /dev/null
if [ $? -ne 0 ]; then
echo "Server down"
else
echo "Server alive"
fi
done
Interesting is that if I iterate the server array instead of the ips array it works. The ips array seems from data fine if printed.
The output if I use the servers array:
1.1.1.1
Server alive
8.8.4.4
Server alive
8.8.8.8
Server alive
4.4.4.4
Server down
and if I use the ips array
1.1.1.1
: Name or service not known
Server down
8.8.4.4
: Name or service not known
Server down
8.8.8.8
: Name or service not known
Server down
4.4.4.4
: Name or service not known
Server down
Output from cat hosts.csv
test;1.1.1.1
test;8.8.4.4
test;8.8.8.8
test;4.4.4.4
First column is for Hostnames and the second column for the IPs in v4.
I am on Ubuntu 20.4.1 LTS
Fixed multiple issues with your code:
Reading of hosts.csv into arrays.
Testing the ping result.
hosts.csv:
one.one.one.one;1.1.1.1
dns.google;8.8.4.4
dns.google;8.8.8.8
invalid.invalid;4.4.4.4
Working commented in code:
#!/usr/bin/env bash
datei=hosts.csv
# Initialize empty arrays
hosts=()
ips=()
# Iterate reading host and ip in line records using ; as field delimiter
while IFS=\; read -r host ip _; do
hosts+=("$host") # Add to the hosts array
ips+=("$ip") # Add to the ips array
done <"$datei" # From this file
# Iterate the index of the ips array
for i in "${!ips[#]}"; do
# Display currently processed host and ip
printf 'Pinging host %s with IP %s\n' "${hosts[i]}" "${ips[i]}"
# Test the result of pinging the IP address
if ping -nc 1 "${ips[i]}" >/dev/null 2>&1; then
echo "Server alive"
else
echo "Server down"
fi
done
You can read into an array from stdin using readarray and so combining this with awk to parse the Host.csv file:
readarray -t ips <<< "$(awk -F\; '{ print $2 }' $date1)"
readarray -t hosts <<< "$(awk -F\; '{ print $1 }' $date1)"

writing the same result for the duplicated values of a column

I'm really new to bash. I have a list of domains in a .txt file (URLs.txt). I also want to have a .csv file which consists of 3 columns separated by , (myFile.csv). My code reads each line of URLs.txt (each domain), finds its IP address and then inserts them into myFile.csv (domain in the first column, its IP in the 2nd column.
Name, IP
ex1.com, 10.20.30.40
ex2.com, 20.30.40.30
ex3.com, 10.45.60.20
ex4.com, 10.20.30.40
Here is my code:
echo "Name,IP" > myFile.csv # let's overwrite, not appending
while IFS= read -r line; do
ipValue= # initialize the value
while IFS= read -r ip; do
if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
ipValue+="${ip}-" # append the results with "-"
fi
done < <(dig +short "$line") # assuming the result has multi-line
ipValue=${ipValue%-} # remove trailing "-" if any
if [[ -n $ipValue ]]; then
# if the IP is not empty
echo "$line,$ipValue" >> myFile.csv
fi
done < URLs.txt
I want to add another column to myFile.csv for keeping open ports of each IP. So output would be like this:
Name, IP, Port
ex1.com, 10.20.30.40, 21/tcp
ex2.com, 20.30.40.30, 20/tcp
ex3.com, 10.45.60.20, 33/tcp
ex4.com, 10.20.30.40, 21/tcp
I want to use Nmap to do this. After I choose an IP address from the 2nd column of myFile.csv and find its open ports using Nmap, I want to write the Nmap result to the corresponding cell of the 3rd column.
Also, if there is another similar IP in the 2nd column I want to write the Nmap result for that line too. I mean I don't want to run Nmap again for the duplicated IP. For example, in my example, there are two "10.20.30.40" in the 2nd column. I want to use Nmap just once and for the 1st "10.20.30.40" (and write the result for the 2nd "10.20.30.40" as well, Nmap should not be run for the duplicated IP).
For this to happen, I changed the first line of my code to this:
echo "Name,IP,Port" > myFile.csv
and also here is the Nmap code to find the open ports:
nmap -v -Pn -p 1-100 $ipValue -oN out.txt
port=$(grep '^[0-9]' out.txt | tr '\n' '*' | sed 's/*$//')
but I don't know what to do next and how to apply these changes to my code.
I updated my code to something like this:
echo "Name,IP" > myFile.csv # let's overwrite, not appending
while IFS= read -r line; do
ipValue= # initialize the value
while IFS= read -r ip; do
if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
ipValue+="${ip}-" # append the results with "-"
fi
done < <(dig +short "$line") # assuming the result has multi-line
ipValue=${ipValue%-} # remove trailing "-" if any
if [[ -n $ipValue ]]; then
# if the IP is not empty
nmap -v -Pn -p 1-100 $ipValue -oN out.txt
port=$(grep '^[0-9]' out.txt | tr '\n' '*' | sed 's/*$//')
echo "$line,$ipValue,$port" >> myFile.csv
fi
done < URLs.txt
but this way, Nmap was used for finding the open ports of the duplicated IPs too, but I didn't want this. What should I do?
Here's a modified version of your script that roughly does what you want:
#!/usr/bin/env bash
# cache maps from IP addresses to open ports
declare -A cache
getports() {
local ip=$1
nmap -v -Pn -p 1-100 "$ip" -oG - \
| awk -F '\t' '
/Ports:/ {
n = split($2, a, /,? /)
printf "%s", a[2]
for (i = 3; i <= n; ++i)
printf ":%s", a[i]
}
'
}
{
echo 'Name,IP,Port'
while IFS= read -r url; do
# Read filtered dig output into array
readarray -t ips < <(dig +short "$url" | grep -E '^([0-9]+\.){3}[0-9]+$')
# Build array of open ports
unset ports
for ip in "${ips[#]}"; do
ports+=("${cache["$ip"]:=$(getports "$ip")}")
done
# Output
printf '%s,%s,%s\n' \
"$url" \
"$(IFS='-'; echo "${ips[*]}")" \
"$(IFS='-'; echo "${ports[*]}")"
done < URLs.txt
} > myFile.csv
The readarray line reads the filtered output from dig into an array of IP addresses; if that array has length zero, the rest of the loop is skipped.
Then, for each elements in the ips array, we get the ports. To avoid calling nmap if we've seen the IP address before, we use the ${parameter:=word} parameter expansion: if ${cache["$ip"]} is non-empty, use it, otherwise call the getports function and store the output in the cache associative array.
getports is called for IP addresses we haven't seen before; I've used -oG ("grepable output") to make parsing easier. The awk command filters for lines containing Ports:, which look something like
Host: 52.94.225.242 () Ports: 80/open/tcp//http/// Ignored State: closed (99)
with tab separated fields. We then split the second field on the regular expression /,? / (an optional comma followed by a blank) and store all but the first field of the resulting array, colon separated.
Finally, we print the line of CSV data; if ips or ports contain more than one element, we want to join the elements with -, which is achieved by setting IFS in the command substitution and then printing the arrays with [*].
The initial echo and the loop are grouped within curly braces so output redirection has to happen just once.

Get hostname mapped to IP Address from file similar to hosts file using BASH

I have a file similar to hosts file where IP Address is mapped to hostname.
Below is a snapshot of file
20.200.80.15 slave1
20.200.80.16 slave2
20.200.80.17 slave3
20.200.80.18 slave4
20.200.80.19 slave5
20.200.80.20 master1
I would like to retrive Hostname from IP Address from the above file using bash script i.e. if I supply ipaddress as 20.200.80.18 then i should get output as slave4
The script could be something like this:
#!/bin/bash
if [ $# -ne 1 ];then
echo "Usage: myscript.sh IP";
exit 1;
fi;
IP=$1
HOSTS_FILE=/root/hosts_test
grep -F "$IP " "$HOSTS_FILE" | awk '{ print $2 }'
exit 0;
And you call it like:
sh myscript.sh 20.200.80.16
It is important to use the -F option in grep (or use fgrep) so te dots are considered as litterals and as not regex wildcards.
I think something like this would work:
#!/bin/sh
ip=$1
file=$2
grep $ip $file | tr -s ' ' | cut -d ' ' -f2
and running the script like this:
getHost 20.20.20.20 /etc/ipfile

iptables 4.12 IP not found: BASH function $line issue

While creating a simple script that grabs a blacklist of ip addresses and blocks them, I came across this issue:
## Function giving greif
function _droplist (){
while read line; do
$IPT -A droplist -i eth1 -s $line -j LOG --log-prefix "IP BlockList "
$IPT -A droplist -i eth1 -s $line -j DROP
done < $badlist ##IPT is /sbin/iptables
}
Through several iterations of this function I get the error:
Try `iptables -h' or 'iptables --help' for more information.
' not found.4.12: host/network `SO.ME.IPH.ERE
Running the same script with hard coded in IP's works fine, its either something to do with $line or m implementation of iptables.
cheers -- Baffled.
What does $badlist contain? A file name or a list of IPs?
if it's a filename it should work as you did it, but if it's a list of ip you have to change how you read them.
Assuming it's a new-line-delimited list of IPs like:
$ badlist="1.1.1.1\n2.2.2.2\n3.3.3.3"
$ echo -e "$badlist"
1.1.1.1
2.2.2.2
3.3.3.3
then you have to modify the loop as follows:
$ echo -e "$badlist"|while read line; do
# do stuff with $line
done
This was an early dive into bash scripting for me the code was also placed remotely on a friends box, the last rough iteration I own of it is on my pastebin:
#!/bin/bash
# ..
# ..
# ..
## Variables
stamp=$(date "+%d/%m/%Y %T")
seed="$RANDOM-$RANDOM-IPTABLES-$(date "+%d-%m-%Y")-TEMPORY" ## proverbial sandpit
log=/root/.IPTables.log; touch $log ## Always a logfile
dmp=/tmp/IPT_DUMP$seed.temp ## Intermediate
list=/tmp/IPT_LIST$seed.txt ## F**ing '\r\r\n' regex'rs
pos=0
## Link(s)
link=http://au.hive.sshhoneypot.com/downloads/iplist.php
## Log File
function _tolog (){
echo -e "$stamp - $#\r" >> $log
}
## Leadin'
_tolog " "
_tolog "-----Running rottweiler : A simple IP deny auto script "
sh -c "iptables --flush"; _tolog "--OK Tables have been flushed"; sleep 1
## Grab-blacklist(s) # Fortran array HO!
function _populate (){
wget $link -O $dmp | egrep '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}' | xargs; _tolog "--OK blacklist stored from honeypot"
tr -d '\r' < $dmp > $list # See above rage comment
while read line; do
arrayIp[$pos]=$line
((pos++))
done < $list
_tolog "--OK IP array created!"
_tolog $(echo -e "---- Array size: ${#arrayIp[*]}")
for item in ${arrayIp[*]}
do
sh -c "/sbin/iptables -I INPUT -s $item -j DROP" # This drops the current blacklist
done; _tolog "--OK Commands passed to iptables DB" # Use: /sbin/iptables -L -v -n to get list back quickly ( no resolving crap )
/sbin/iptables-save > /root/iptables.backup; _tolog "--OK Table database saved to flatfile"
}
_populate
_tolog "-----Terminating script: Tables logged in ~/iptables.backup"
Had similar issues resulting from Windows line endings (\r\n). Converting to unix endings (\n) solved my problem.
Cheers, /phfff

How to get the primary IP address of the local machine on Linux and OS X? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 4 years ago.
Improve this question
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.
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.
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
For linux machines (not OS X) :
hostname --ip-address
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.
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.
Edited (2014-06-01 2018-01-09 2021-07-25)
From some time ago, I use now newer ip tool. But under bash, 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 bash 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
Specific to only certain builds of Ubuntu. Though it may just tell you 127.0.0.1:
hostname -i
or
hostname -I
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
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
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}'
ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}'
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.
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
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
The shortest way to get your local ipv4-address on your linux system:
hostname -I | awk '{print $1}'
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.
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
ip addr show | grep -E '^\s*inet' | grep -m1 global | awk '{ print $2 }' | sed 's|/.*||'
Another ifconfig variantion that works both on Linux and OSX:
ifconfig | grep "inet " | cut -f2 -d' '
Not sure if this works in all os, try it out.
ifconfig | awk -F"[ :]+" '/inet addr/ && !/127.0/ {print $4}'
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
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.
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.
If you know the network interface (eth0, wlan, tun0 etc):
ifconfig eth0 | grep addr: | awk '{ print $2 }' | cut -d: -f2
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
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]*'
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}')}
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.
This is easier to read:
ifconfig | grep 'inet addr:' |/usr/bin/awk '{print $2}' | tr -d addr:
If you have npm and node installed : npm install -g ip && node -e "const ip = require('ip'); console.log(ip.address())"

Resources