Reputation: 833
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
Reputation: 88591
With GNU grep:
grep '^[^;].*Serial Number' file | grep -o '2016[0-9]\{6\}'
Output:
2016071602
Upvotes: 1
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
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