6

I want to split up a variable using awk by a colon, but only the last variable.

From this input:

 ACCEPT     tcp  --  0.0.0.0/0     0.0.0.0/0     tcp dpt:22

I want the following output:

 protocol=tcp source=0.0.0.0/0 destination=0.0.0.0/0 port=22

This is my awk command now:

 awk '/^ACCEPT/ {print "protocol=",$2, "source=",$4,"destination=",$5,"port=",$7}"

Which produces:

protocol=tcp source=0.0.0.0/0 destination=0.0.0.0/0 port=dpt:22

But I want to get 22 out of $7 and not dpt:22

I've tried using awk's field separator, but I can figure out how to make it only apply to a single variable

codeforester
  • 39,467
  • 16
  • 112
  • 140
hamiltionxc
  • 63
  • 1
  • 5

5 Answers5

5

Just tweak FS to include the :

$ echo 'ACCEPT     tcp  --  0.0.0.0/0     0.0.0.0/0     tcp dpt:22' |
     awk '/^ACCEPT/{printf("protocol=%s source=%s destination=%s port=%s\n", $2,$4,$5,$8)}
     ' FS='[ :]*'
protocol=tcp source=0.0.0.0/0 destination=0.0.0.0/0 port=22

You might need to include tabs, and do FS='[ :\t]*'

William Pursell
  • 204,365
  • 48
  • 270
  • 300
2

You can use a regex to define a custom field separators in awk.

some_command | awk -F '[[:blank:]:]+' '/^ACCEPT/{
   printf "protocol=%s source=%s destination=%s port=%s\n", $2, $4, $5, $NF}'

protocol=tcp source=0.0.0.0/0 destination=0.0.0.0/0 port=22

-F '[[:blank:]:]+' sets input field separator as one of white-space or colon.

anubhava
  • 761,203
  • 64
  • 569
  • 643
1

Use the following awk approach:

awk '{ printf "protocol=%s source=%s destination=%s port=%s\n",$2,$4,$5,substr($7,5) }' file

But if the last field has dynamic prefix length you may apply gsub() function to remove non-digit characters:

awk '{ gsub(/^[^0-9]+/,"",$7); printf "protocol=%s source=%s destination=%s port=%s\n",$2,$4,$5,$7 }' file
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
1

slight modification in your awk command

$ awk '/^ACCEPT/ {gsub(/[^0-9]/,"",$7); print "protocol="$2, "source="$4,"destination="$5,"port="$7}' file
protocol=tcp source=0.0.0.0/0 destination=0.0.0.0/0 port=22

gsub(/[^0-9]/,"",$7); will nullify all non-digit characters in $7

Rahul Verma
  • 2,946
  • 14
  • 27
0

awk has a split function to break a string (argument 1) up into an array of fields (argument 2) using a specified delimiter regexp (argument 3).

The following awk program will scan all the iptables options (field 6 through the last field of the line), rather than relying on dpt:### being the 7th field.

awk '/^ACCEPT/ {
                 port="???"
                 for (i=6; i<=NF; i++) {
                   if (split($i, opt, ":")==2 && opt[1]=="dpt") {
                      port=opt[2]
                   }
                 }
                 print "protocol=" $2, "source=" $4, "destination=" $5, "port=" port
               }'
Mark Plotnick
  • 9,598
  • 1
  • 24
  • 40