0

Im trying to develop a script that finds a specific pattern in the output of the dig command running against a list of domains. To do this I'm using grep but having difficulty implementing this using multiple logical operations.

I want to achieve something like this:

if output contains ("NXDOMAIN") and ("test1.com" or "test2.com"); then
echo output;

I have managed to get it working for the pattern "NXDOMAIN" by piping the output into grep but I am lost on how to implement the logical operators. My script so far:

#!/bin/bash
input="/root/subdomains.txt"
while IFS= read -r line
do
    output=$(dig "$line")
    if echo "$output" | grep "NXDOMAIN" >&/dev/null; then
        echo "$output";
    else
        echo " " >&/dev/null;
    fi
done < "$input"

Is using grep the best way to achieve this?

2

No need for grep or bash here.

#!/bin/sh -
input="/root/subdomains.txt"

contains() {
  case "$1" in
    (*"$2"*) true;;
    (*) false;;
  esac
}

while IFS= read <&3 -r line
do
    output=$(dig "$line")
    if
      contains "$output" NXDOMAIN && {
        contains "$output" test1.com || contains "$output" test2.com
      }
    then
      printf '%s\n' "$output"
    fi
done 3< "$input"

If you really wanted to use grep, you'd define contains as:

contains() {
  printf '%s\n' "$1" | grep -qFe "$2"
}

But that would be less efficient as it means spawning two extra processes and in most sh implementation executing an external grep utility.

Or:

#!/bin/sh -
input="/root/subdomains.txt"

match() {
  case "$1" in
    ($2) true;;
    (*) false;;
  esac
}

while IFS= read <&3 -r line
do
    output=$(dig "$line")
    if
      match "$output" '*NXDOMAIN*' &&
        match "$output" '*test[12].com*'
    then
      printf '%s\n' "$output"
    fi
done 3< "$input"

Or do without the intermediary function:

#!/bin/sh -
input="/root/subdomains.txt"

while IFS= read <&3 -r line
do
    output=$(dig "$line")
    case $output in
      (NXDOMAIN)
        case $output in
          (test1.com | test2.com) printf '%s\n' "$output"
        esac
    esac
done 3< "$input"

That would also work with bash, but there's no need to add a dependency to bash when your (presumably faster and leaner) standard sh can do it.

  • thank you for the detailed answer. "match" seemed to do the trick for me – PjMpire Jun 5 at 9:15
0

You can create a logical AND by piping into grep again, and a logical OR using regular expressions:

echo "$output" | grep "NXDOMAIN" | grep -E 'test1\.com|test2\.com'
  • 1
    grep -E "[test1.com|test2.com]" looks for any single character in the set t e s 1 . c o m | 2. You'd need grep -E 'test1\.com|test2\.com' or grep 'test[12]\.com' to look for either test1.com or test2.com – Stéphane Chazelas Jun 5 at 8:46
  • 2
    That approach only works if the NXDOMAIN and test[12].com are on the same line. – Stéphane Chazelas Jun 5 at 8:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.