Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grep and print back reference

I have this iptable log:

Feb 25 10:32:48 XXX: [414645.555838] FW: DEN TCP IN=eth0 OUT= MAC=XYZ SRC=1.1.1.1 DST=2.2.2.2 LEN=40 TOS=0x00 PREC=0x00 TTL=57 ID=0 DF PROTO=TCP SPT=80 DPT=51814 WINDOW=0 RES=0x00 RST URGP=0

I want to grep 1.1.1.1 and 80 (SRC and SPT field). I do this:

grep -oP 'SRC=([^ ]+).+SPT=([0-9]+)' /var/log/iptables.log

But it returns:

SRC=1.1.1.1 DST=2.2.2.2 LEN=40 TOS=0x00 PREC=0x00 TTL=57 ID=0 DF PROTO=TCP SPT=80

How do I get $1 and $2 only ( reference to the matched value)?

like image 836
w00d Avatar asked Dec 02 '22 20:12

w00d


2 Answers

The main issue with your example is that you are trying to return groupings, this is not possible IIUC. One way around this is to use positive look-behind (see man perlre):

grep -oP '(?<=SRC=|SPT=)[^ ]*'

Output:

1.1.1.1
80

Here's a more portable alternative:

grep -o 'SRC=[^ ]*\|SPT=[^ ]*' | grep -o '[^=]*$'

If you want the output to be on one line, you should consider going one tool up, i.e. use Lev's answer. If you know that the output always comes in pairs, you could join the lines with paste:

grep -oP '(?<=SRC=|SPT=)[^ ]*' | paste - -

Or with xargs:

grep -oP '(?<=SRC=|SPT=)[^ ]*' | xargs -n2

Or sed:

grep -oP '(?<=SRC=|SPT=)[^ ]*' | sed 'N; s/\n/ /'
like image 80
Thor Avatar answered Dec 20 '22 09:12

Thor


A sed approach:

sed -rn 's/.*SRC=([^ ]+).*SPT=([0-9]+).*/\1 \2/p' /var/log/iptables.log

You can pipe it to while read src spt in your script or something similar. Now this of course is not very efficient, because of three stars in the pattern, so if performance is an issue, you can consider using things like cut to extract certain fields:

cut -d' ' -f12,21 /var/log/iptables.log

Not sure if the log format is consistent enough for this to work.

like image 39
Lev Levitsky Avatar answered Dec 20 '22 09:12

Lev Levitsky