john wilson john wilson - 4 months ago 29
Linux Question

Trouble doing grep only 10 digit number from a file

I am unable to grep exact only 10 digit number I wanted from a zone file.

Example zone file is:

> cat /var/named/test.com.db
; cPanel first:11.11.0-BETA_16994 (update_time):1468656855 Cpanel::ZoneFile::VERSION:1.3 hostname:server.test.com latest:11.56.0.13
; Zone file for test.com
$TTL 14400
test.com. 86400 IN SOA ns1.test.com. cpanel.test.com. (
2016071602 ;Serial Number
14400 ;refresh
7200 ;retry
2419200 ;expire
43200 )
; test.com. 86400 IN SOA ns1.test.com. serveralerts.test.com. ( ; Previous value removed by cPanel restore auto-merge on 20160510102706 GMT
; 2015061700 ;Serial Number ; Previous value removed by cPanel restore auto-merge on 20160510102706 GMT
; 86400 ;refresh ; Previous value removed by cPanel restore auto-merge on 20160510102706 GMT
; 7200 ;retry ; Previous value removed by cPanel restore auto-merge on 20160510102706 GMT
; 3600000 ;expire ; Previous value removed by cPanel restore auto-merge on 20160510102706 GMT
; 86400 ;minimum ; Previous value removed by cPanel restore auto-merge on 20160510102706 GMT
; ) ; Previous value removed by cPanel restore auto-merge on 20160510102706 GMT

test.com. 86400 IN NS ns1.test.com.
test.com. 86400 IN NS ns2.test.com.
; test.com. 86400 IN NS ns1.test.com. ; Previous value removed by cPanel restore auto-merge on 20160510102706 GMT
; test.com. 86400 IN NS ns2.test.com. ; Previous value removed by cPanel restore auto-merge on 20160510102706 GMT


test.com. 14400 IN A 192.168.1.100

localhost 14400 IN A 127.0.0.1

test.com. 14400 IN MX 0 test.com.

mail 14400 IN CNAME test.com.
www 14400 IN CNAME test.com.
ftp 14400 IN CNAME test.com.
webdisk 14400 IN A 192.168.1.100
cpcalendars 14400 IN A 192.168.1.100
test.com. IN TXT "v=spf1 +a +mx +ip4:192.168.1.100 ~all"


I want to see only the current serial number 2016071602 from the zone file on grep output.

For that I tried the command:

grep -o '2016[0-9]\{6\}' /var/named/test.com.db


But it outputs all those trash. I meant even digits with length more than 10

The result I am getting is:

> grep -o '2016[0-9]\{6\}' /var/named/test.com.db
2016071602
2016051010
2016051010
2016051010
2016051010
2016051010
2016051010
2016051010
2016051010
2016051010


Could you help me to filter this out properly?. Once I able to correct this one, I will be happy to proceed with mass zones update on the server.

Answer

grep is not the best tool if you need a context, that is, some text around the pattern without including that text in the output. sed with capture groups will work better, for example:

sed -ne 's/.*\(2016[0-9]\{6\}\).*Serial Number.*/\1/p' filename

This will print out the pattern captured within \(...\), when followed by "Serial Number" on the same line. If this is not yet good enough, you can adjust the pattern accordingly, making it more strict to eliminate further false positives.

Another useful trick is enclosing the interesting pattern within \<...\> to make it match word boundaries:

sed -ne 's/.*\<\(2016[0-9]\{6\}\)\>.*Serial Number.*/\1/p' filename

This way, cases like digits before 2016 or longer than 10 digits will not match.

Comments