Need to grep only IP Address - shell

nslookup google.com
Server: xx.xx.xx.xx
Address: xx.xx.xxx.xx#53
Non-authoritative answer:
Name: google.com
Address: 172.217.164.110
I just need the last IP Address with grep/awk like below, please help.
172.217.164.110

Can be enhanced, but it'll do what you want:
nslookup google.com | sed -n '/Name:/{x;n;p;d;}; x' | awk '{print $2}'
Output (when only one Name+Address block is returned by nslookup):
172.217.164.110
I used sed's pattern space advanced options, printing the line following the "Name: google.com" line (x;n;p; sequence after "Name:" pattern match). I am not a sed guru, I used this Unix Stack Exchange answer, then awk to get only the IP following a whitespace.
In a IPv6 setting, you can get both the IPv4 and the IPv6 addresses, in two lines, so if this is not what you want, you will have to filter out the IPv6, using a pattern that only matches the format of an IPv4.

Related

How to filter the first Ip from a 5 tuple that is present in every line in Linux

I would like to filter the first IP from the given output below.
3676798 I/H 628 71.1.219.106 10198 71.1.208.58 20198 UDP A
3676798 R/U 628 71.1.208.58 20198 71.1.219.106 10198 UDP A
3676799 I/H 1066 71.1.57.57 10008 71.1.57.53 20008 UDP A
3676799 R/U 1066 71.1.57.53 20008 71.1.57.57 10008 UDP A
3676800 I/H 532 71.1.213.104 10142 71.1.203.52 20142 UDP A
3676800 R/U 532 71.1.203.52 20142 71.1.213.104 10142 UDP A
Using the below command, I'm able to get all the IP's but I would like to get only the first ip from each line which has 2 IP's. There may be line which might not have IP's at all. so I would like to ignore that line.
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' <filename>
I tried to use Awk to get it (as suggested in one of the comments) but this was unsuccessful since it prints the fourth field from any line which does not have IP's as well.
awk '{ print $4 }' file
Any pointers would be highly helpful.
To only print when the fourth field matches an IP address,
awk '$4 ~ /^[1-9][0-9]{1,2}(\.[0-9]{1,3}){3}$/{ print $4 }' file
To only print the first IP address on any line, regardless of where exactly it's found, try Perl:
perl -ne 's/.*?([0-9]{1,3}(\.[0-9]{1,3}){3}).*/$1/ and print' file
This looks quite similar to sed but the non-greedy .*? is not available in sed. If you wanted the last IP address on every line, it would be easy to do with sed.

Fetch value after certain pattern in Unix

This is the text that I have
Peer Addr 1.1.1.1, Intf Port-Channel0.1, State Up
VRF default, LAddr 1.1.1.1, LD/RD 090/592
Session state is Up and using echo function with 300 ms interval
Detect Time: 8000
Sched Delay: 1*TxInt: 3522100, 2*TxInt: 5, 3*TxInt: 0, GT 3*TxInt: 0
Registered protocols: isis bgp ospf
I want the values after Peer Addr, Intf and Registered protocols
Expected output
1.1.1.1
Port-Channel0.1
isis bgp ospf
This is what I have tried
grep -oP "Peer Addr\s+\K\w+"
I am unable to get the required output. I am new to shell scripting and would be great if someone can help me out on this one. I don't want all the output in a single command. I would like to store these as three different variables
With GNU awk for multi-char RS:
$ awk -v RS='[\n,]\\s*' 'sub(/^(Peer Addr|Intf|Registered protocols:) /,"")' file
1.1.1.1
Port-Channel0.1
isis bgp ospf
With GNU grep:
grep -Po '(Peer Addr|Intf|protocols:) \K.*?(?=(,|$))' file
Output:
1.1.1.1
Port-Channel0.1
isis bgp ospf
-P PATTERN: Interpret PATTERN as a Perl regular expression.
-o: Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.
\K: If \K appears in a Perl regex, it causes the regex matcher to drop everything before that point.
(?=...): The captured match must be followed by , or end of line ($) but that part is dropped, too.
With sed, you could do something like this:
sed -rn 's/Peer Addr *([^,]+), */\1/;
s/Intf *([^,]+),.*/\n\1/;
s/Registered protocols: *//;
ta;d;:a p'
awk -F"[, ]" '/^Peer Addr/{print $3"\n"$6} /^Registered protocols:/{sub(/Registered protocols: /,"");print}' File
Here IFS as , and .
/^Peer Addr/{print $3"\n"$6} : If a line starts with Peer Addr print $3( Here 1.1.1.1) and $6( Port-Channel0.1).
/^Registered protocols:/{sub(/Registered protocols: /,"");print}': If a line starts with Registered protocols: print entire line after removing the string Registered protocols: with sub awk function.

Portable way to resolve host name to IP address

I need to resolve a host name to an IP address in a shell script. The code must work at least in Cygwin, Ubuntu and OpenWrt(busybox).
It can be assumed that each host will have only one IP address.
Example:
input
google.com
output
216.58.209.46
EDIT:
nslookup may seem like a good solution, but its output is quite unpredictable and difficult to filter. Here is the result command on my computer (Cygwin):
>nslookup google.com
Unauthorized answer:
Serwer: UnKnown
Address: fdc9:d7b9:6c62::1
Name: google.com
Addresses: 2a00:1450:401b:800::200e
216.58.209.78
I've no experience with OpenWRT or Busybox but the following one-liner will should work with a base installation of Cygwin or Ubuntu:
ipaddress=$(LC_ALL=C nslookup $host 2>/dev/null | sed -nr '/Name/,+1s|Address(es)?: *||p')
The above works with both the Ubuntu and Windows version of nslookup. However, it only works when the DNS server replies with one IP (v4 or v6) address; if more than one address is returned the first one will be used.
Explanation
LC_ALL=C nslookup sets the LC_ALL environment variable when running the nslookup command so that the command ignores the current system locale and print its output in the command’s default language (English).
The 2>/dev/null avoids having warnings from the Windows version of nslookup about non-authoritative servers being printed.
The sed command looks for the line containing Name and then prints the following line after stripping the phrase Addresses: when there's more than one IP (v4 or 6) address -- or Address: when only one address is returned by the name server.
The -n option means lines aren't printed unless there's a p commandwhile the-r` option means extended regular expressions are used (GNU sed is the default for Cygwin and Ubuntu).
If you want something available out-of-the-box on almost any modern UNIX, use Python:
pylookup() {
python -c 'import socket, sys; print socket.gethostbyname(sys.argv[1])' "$#" 2>/dev/null
}
address=$(pylookup google.com)
With respect to special-purpose tools, dig is far easier to work with than nslookup, and its short mode emits only literal answers -- in this case, IP addresses. To take only the first address, if more than one is found:
# this is a bash-specific idiom
read -r address < <(dig +short google.com | grep -E '^[0-9.]+$')
If you need to work with POSIX sh, or broken versions of bash (such as Git Bash, built with mingw, where process substitution doesn't work), then you might instead use:
address=$(dig +short google.com | grep -E '^[0-9.]+$' | head -n 1)
dig is available for cygwin in the bind-utils package; as bind is most widely used DNS server on UNIX, bind-utils (built from the same codebase) is available for almost all Unix-family operating systems as well.
Here's my variation that steals from earlier answers:
nslookup blueboard 2> /dev/null | awk '/Address/{a=$3}END{print a}'
This depends on nslookup returning matching lines that look like:
Address 1: 192.168.1.100 blueboard
...and only returns the last address.
Caveats: this doesn't handle non-matching hostnames at all.
TL;DR; Option 2 is my preferred choice for IPv4 address. Adjust the regex to get IPv6 and/or awk to get both. There is a slight edit to option 2 suggested use given in EDIT
Well a terribly late answer here, but I think I'll share my solution here, esp. because the accepted answer didn't work for me on openWRT(no python with minimal setup) and the other answer errors out "no address found after comma".
Option 1 (gives the last address from last entry sent by nameserver):
nslookup example.com 2>/dev/null | tail -2 | tail -1 | awk '{print $3}'
Pretty simple and straight forward and doesn't really need an explanation of piped commands.
Although, in my tests this always gave IPv4 address (because IPv4 was always last line, at least in my tests.) However, I read about the unexpected behavior of nslookup. So, I had to find a way to make sure I get IPv4 even if the order was reversed - thanks regex
Option 2 (makes sure you get IPv4):
nslookup example.com 2>/dev/null | sed 's/[^0-9. ]//g' | tail -n 1 | awk -F " " '{print $2}'
Explanation:
nslookup example.com 2>/dev/null - look up given host and ignore STDERR (2>/dev/null)
sed 's/[^0-9. ]//g' - regex to get IPv4 (numbers and dots, read about 's' command here)
tail -n 1 - get last 1 line (alt, tail -1)
awk -F " " '{print $2} - Captures and prints the second part of line using " " as a field separator
EDIT: A slight modification based on a comment to make it actually more generalized:
nslookup example.com 2>/dev/null | printf "%s" "$(sed 's/[^0-9. ]//g')" | tail -n 1 | printf "%s" "$(awk -F " " '{print $1}')"
In the above edit, I'm using printf command substitution to take care of any unwanted trailing newlines.

sed: replace ip in hosts file, using hostname as pattern

I'm learning about sed but it is very difficult to me understand it.
I have adsl with dynamic ip so and i want to put current ip on hosts file.
This following script just tells me the current wan ip address and no more:
IP=$(dig +short myip.opendns.com #resolver1.opendns.com)
echo $IP
The result:
192.42.7.73
So, i have a line on hosts file with the old ip address:
190.42.44.22 peep.strudel.com
and i want to update host file like this:
192.42.7.73 peep.strudel.com
How can i do it? I think i can use the hostname as pattern...
The reason of doing this is because my server is a client of my router, so it access the internet thru its gateway and not directly. And postfix always is logging me that "connect from unknown [x.x.x.x]" (where x.x.x.x is my wan ip!) and it can't resolve that ip. I think that maybe if i specify this relating with my fqdn host/domain, on hosts file it will works better.
Thanks
Sergio.
You can use a simple shell script:
#! /bin/bash
IP=$(dig +short myip.opendns.com #resolver1.opendns.com)
HOST="peep.strudel.com"
sed -i "/$HOST/ s/.*/$IP\t$HOST/g" /etc/hosts
Explanation:
sed -i "/$HOST/ s/.*/$IP\t$HOST/g" /etc/hosts means in the line which contains $HOST replace everything .* by $IP tab $HOST.
using sed
sed -r "s/^ *[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+( +peep.strudel.com)/$IP\1/"
.
[0-9]+\. find all lines that matches 1 or more digits with this pattern 4 consecutive times then pattern peep.strudel.com .The parenthesis around the pattern peep.strudel.com save it as \1 then replace the whole patten with your variable and your new ip.
another approach:instead of saving pattern to a variable named IP, you can execute your command line inside sed command line to get the new IP .
sed -r "s/^ *[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+( +peep.strudel.com)/$(dig +short myip.opendns.com #resolver1.opendns.com)\1/"
using gawk
gawk -v IP=$IP '/ *[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+( +peep.strudel.com).*/{print gensub(/ *[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+( +peep.strudel.com)/,IP"\\1","g")}'
You need to include the sed code inside double quotes so that the used variable got expanded.
sed "s/\b\([0-9]\{1,3\}\.\)\{1,3\}[0-9]\{1,3\}\b/$IP/g" file
Add -i parameter to save the changes made. In basic sed \(..\) called capturing group. \{min,max\} called range quantifier.
Example:
$ IP='192.42.7.73'
$ echo '190.42.44.22 peep.strudel.com' | sed "s/\b\([0-9]\{1,3\}\.\)\{1,3\}[0-9]\{1,3\}\b/$IP/g"
192.42.7.73 peep.strudel.com

tcpdump - ignore unkown host error

I've got a tcpdump command running from a bash script. looks something like this.
tcpdump -nttttAr /path/to/file -F /my/filter/file
The filter file has a combination of ip addresses and host names. i.e.
host 111.111.111.111 or host 112.112.112.112 and not (host abc.com or host def.com or host zyx.com).
And it works great - as long as the host names are all valid. My problem is sometimes these hostnames will not be valid and upon encountering one - tcpdump spits out
tcpdump: Unknown Host
I thought with the -n option it would skip dns lookup - but in anycase I need it to ignore the unknown host and continue along the filter file.
Any ideas?
Thank you in advance.
The -n option prevents conversion of IP addresses into names, but not the other way around. If you supply a hostname as an argument, it has to be looked up to get the IP address since packets only contain the numeric address and not the hostname. However, there ought to be a way to ignore invalid hostnames, but I can't find one. Perhaps you could pre-process your filter file using dig.
dig +short non-existent-domain.com # returns null
dig +short google.com # returns multiple IP addresses
This could probably be better, but it should show you hostnames in your filter file that aren't valid:
grep -Po '(?<=host )[^ )]*' filterfile | grep -v '[0-9]$' | xargs -I % sh -c 'echo -n "% "; echo $(dig +short %)' | grep -v ' [0-9]'
Any hostnames it prints didn't have IP addresses returned by dig.

Resources