vjwilson
vjwilson

Reputation: 833

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.

Upvotes: 4

Views: 2865

Answers (3)

Cyrus
Cyrus

Reputation: 88591

With GNU grep:

grep '^[^;].*Serial Number' file | grep -o '2016[0-9]\{6\}'

Output:

2016071602

Upvotes: 1

John1024
John1024

Reputation: 113834

The issue is that 2016[0-9]\{6\} matches any ten digits that begin with 2016. It places no limitations on what comes before or after those digits.

Try:

$ grep -Eo '2016[0-9]{6}[^0-9]' test.com.db 
2016071602 

Or, better yet, if your grep supports -P, as it does on Linux systems:

$ grep -Po '2016[0-9]{6}(?=[^0-9])' test.com.db 
2016071602

Here, (?=[^0-9]) is a look-ahead: it requires that a non-digit follow the number but it is not be included in the match.

Or, to get the number that is followed by "Serial Number":

$ grep -Po '2016[0-9]{6}(?=.*Serial Number)' test.com.db 
2016071602

This requires that the character after the ten digit number must be a non-digit. ([^0-9] matches any non-digit because the ^ is the negation of what follows it.)

To make sure that this works with unicode fonts, you may want to replace [0-9] with its unicode-safe alternative: [[:digit:]]:

$ grep -Po '2016[[:digit:]]{6}(?=[^[:digit:]])' test.com.db 
2016071602

Upvotes: 4

janos
janos

Reputation: 124646

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.

Upvotes: 1

Related Questions