2

in my usecase i'm filtering certain IPv4s from the list and putting them into array for further tasks:

readarray -t firstarray < <(grep -ni '^ser*' IPbook.file | cut -f 2 -d "-")

As a result the output is:

10.8.61.10
10.0.10.15
172.0.20.30
678.0.0.10

As you see the last row is not an IP, therefore i faced an urge to add some regex check on the FIRSTARRAY. I do not want to save a collateral files to work with them, so i'm looking for some "on-the-fly" option to regex the firstarray. I tried the following:

for X in "${FIRSTARRAY[@]}"; do
  readarray -t SECONDARRAY < <(grep -E '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}\b' "$X")
done

But in the output I see that system thinks that $X is a file/dir, and didn't process the value, even though it clearly sees it:

line ABC: 172.0.20.30: No such file or directory
line ABC: 678.0.0.10: No such file or directory

What am I doing wrong and what would be the best approach to proceed?

codeforester
  • 39,467
  • 16
  • 112
  • 140
faceless
  • 450
  • 4
  • 15

2 Answers2

2

You are passing "$X" as an argument to grep and hence it is being treated as a file. Use herestring <<< instead:

for X in "${firstarray[@]}"; do
  readarray -t secondarray < <(grep -E '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}\b' <<< "$X")
done

You are better off writing a function to validate the IP instead of relying on just a regex match:

#!/bin/bash
validate_ip() {
  local arr element
  IFS=. read -r -a arr <<< "$1"                  # convert ip string to array
  [[ ${#arr[@]} != 4 ]] && return 1              # doesn't have four parts
  for element in "${arr[@]}"; do
    [[ $element =~ ^[0-9]+$ ]]       || return 1 # non numeric characters found
    [[ $element =~ ^0[1-9]+$ ]]      || return 1 # 0 not allowed in leading position if followed by other digits, to prevent it from being interpreted as on octal number
    ((element < 0 || element > 255)) && return 1 # number out of range
  done
  return 0
}

And then loop through your array:

for x in "${firstarray[@]}"; do
  validate_ip "$x" && secondarray+=("$x") # add to second array if element is a valid IP
done
codeforester
  • 39,467
  • 16
  • 112
  • 140
1

The problem is, that you passing an argument to the grep command and it expects reading standard input instead.

You can use your regex to filter the IP addresses right in the first command:

readarray -t firstarray < <(grep -ni '^ser*' IPbook.file | cut -f 2 -d "-" | grep -E '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}\b' )

Then you have only IP addresses in firstarray.

buff
  • 2,063
  • 10
  • 16