Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

awk create a list for testing elements

Tags:

awk

I have a list of discrete elements that I want to test inclusion of an entry from each line of my file. I'd like a succinct way to create a list or array in awk and then test each line against that list.

My list of discrete elements:

ports=(1010, 2020, 3030, 8888, 12345)

myFile:

127.0.0.1 1010
127.0.0.1 1011
127.0.0.1 12345
127.0.0.1 3333

My pseudocode:

awk '
  BEGIN {
    test_ports=[1010, 2020, 3030, 8888, 12345]
  }
  ($2 in test_ports) {
    print $0
  }
' myFile

The code below works, but it is not succinct and I don't like how it grows as the list grows, like if I get 100 ports to test against, or 1000...

awk '
  BEGIN {
    test_ports["1010"]=1
    test_ports["2020"]=1
    test_ports["3030"]=1
    test_ports["8888"]=1
    test_ports["12345"]=1
  }
  ($2 in test_ports) {
    print $0
  }
' myFile

Something like this would be good too, but the syntax isn't quite right:

for i in 1010 2020 3030 8888 12345 {test_ports[i]=1}

EDIT

This code works too and is very close to what I need, but it still seems a bit long for what it's doing.

awk '
  BEGIN {
    ports="1010,2020,3030,8888,12345"
    split(ports, ports_array, ",")
    for (i in ports_array) {test_ports[ports_array[i]] = 1}
  }
  ($2 in test_ports) {
    print $0
  }
' myFile
like image 858
Rusty Lemur Avatar asked Mar 16 '26 19:03

Rusty Lemur


2 Answers

You may use it like this:

awk '
  BEGIN {
    ports = "1010 2020 3030 8888 12345"  # ports string
    split(ports, temp)                   # split by space in array temp 
    for (i in temp)                      # populate array test_ports
       test_ports[temp[i]]
  }

  $2 in test_ports                       # print rows with matching ports
' myFile
127.0.0.1 1010
127.0.0.1 12345

A note of explanation:

  • temp is a numerically indexed array where the ports (1010, 2020, etc) are the array values, indexed from 1
  • test_ports is an associative array where the ports are the array keys and the values are null.
  • the elem in array operator tests if the given element is an index (aka "subscript") of the array.

Addendum: You also have option of reading ports from a file if your ports list is big like this:

awk 'NR == FNR {ports[$1]; next} $2 in ports' ports.list myfile

Or else if you have ports saved in a string then use:

ports='1010 2020 3030 8888 12345'
awk 'NR==FNR{ports[$1]; next} $2 in ports' <(printf '%s\n' $ports) myfile
127.0.0.1 1010
127.0.0.1 12345
like image 147
anubhava Avatar answered Mar 19 '26 10:03

anubhava


Since you said I'd like a succinct way to create a list or array in awk and then test each line against that list, here is a succinct way to create a list in awk and then test each line against that list:

$ awk 'index(",1010,2020,3030,8888,12345,",","$2",")' file
127.0.0.1 1010
127.0.0.1 12345

or if you prefer:

$ awk -v ports='1010,2020,3030,8888,12345' 'index(","ports",",","$2",")' file
127.0.0.1 1010
127.0.0.1 12345
like image 38
Ed Morton Avatar answered Mar 19 '26 10:03

Ed Morton



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!