Rafki Altoberi
Rafki Altoberi

Reputation: 13

Selecting substring inside string in bash

I'm totally new in shell scripting and trying to extract substring inside the string that user input. I have file a.txt that contains:

abc.com
div.abc.com

now if the user give input www.abc.com then I want to select abc.com from that file and put abc.com into a variable. and if the user gives input prod.div.abc.com then I want to select div.abc.com from that file and put div.abc.com into a variable.

I try to use:

while read line; do
  bc=$(echo $fq | grep -P '^('$line'!?)')
  if [[ $fq =~ $bc ]]
        then
        echo $line
  fi
done <a.txt

Seems the output is far from my expectation.

Upvotes: 1

Views: 255

Answers (3)

L&#233;a Gris
L&#233;a Gris

Reputation: 19545

Using Bash4's associative array, it is more efficient to store your domains file a.txt as an associative array keys (or dictionary keys).

#!/usr/bin/env bash

declare -r domain_names_file='a.txt'

# shellcheck disable=SC2155 # Safe assignment of associative array keys
declare -rA domain_keys="($(
  # Transforms the domain_names lines from the file into associative array keys
  # of domain names while stripping-out the trailing dot if any.
  # Allows fast checking a domain name.
  sed <"$domain_names_file" 's/\.$//' | xargs -l1 printf '[%q]= '
))"

# Matches argument against domain keys
# @Globals:
# domain_keys: The associative array containing
#   dictionary keys of domains to match against
# @Args:
# 1: The domainks to check
# @Output:
# >&1: Matching domain
# @Return
# false if no matching domain found
match_domain() {
  # Strip trailing dot of FQDN if any
  local -- domain="${1%.}"
  while [[ $domain =~ [^.]+\.?(.*) ]]; do
    if [[ "${domain_keys[$domain]+isset}" ]]; then
      echo "$domain"
      return
    fi
    # RegEx Match capture group 1 contains the domain name stripped of
    # its leading sub-domain if any. So lets continue with it...
    domain="${BASH_REMATCH[1]}"
  done
  # No match found, returns false
  false
}

while read -r -p 'Enter domain name to check (or CTRL+D to quit): ' reply; do
  # Get domain match
  if matched_domain="$(match_domain "$reply")"; then
    printf 'Found domain: %q\n' "$matched_domain"
  else
    printf 'No domain match for %q\n' "${reply%.}"
  fi
done

echo

Lets test it

Populate a.txt:

cat >a.txt <<EOF
example.com
div.example.com.
localhost
localhost.localdomain
EOF

Run the script use CTRL+d to stop:

Enter domain name to check (or CTRL+D to quit): www.example.com.
Found domain: example.com
Enter domain name to check (or CTRL+D to quit):  example.com
Found domain: example.com
Enter domain name to check (or CTRL+D to quit): sub.div.example.com
Found domain: div.example.com
Enter domain name to check (or CTRL+D to quit): sub2.sub1.div.example.com
Found domain: div.example.com
Enter domain name to check (or CTRL+D to quit): localhost.
Found domain: localhost
Enter domain name to check (or CTRL+D to quit): localhost.localdomain.
Found domain: localhost.localdomain
Enter domain name to check (or CTRL+D to quit): does.not.exist
No domain match for does.not.exist

Upvotes: 1

rtx13
rtx13

Reputation: 2610

I'm assuming that read is intended to get user input, while a.txt has the list of patterns to match:

while read line; do
  if match=$(printf %s "$line" | grep -F -o -f a.txt) ; then
    var="$match"
    printf "match is %s\n" "$match"
  fi
done

The options to grep are:

  • -F — match fixed strings
  • -o — print only matched portion
  • -f a.txt — read patterns (fixed strings) from file a.txt

Upvotes: 0

Jetchisel
Jetchisel

Reputation: 7781

You can try capturing the input from the user using read and then use grep to search for the match.

#!/usr/bin/env bash

file=a.txt

read -rp 'Enter input ' input

if var=$(grep -x "${input#*.}" "$file") || var=$(grep -x "$input" "$file"); then
  echo "$var"
else
  echo "$input not found in $file" >&2
fi
  • This assumes that your file has one entry per-line.

  • If there is a match it will be in the "$var"

  • Both input can have the leading prod. and www.

Upvotes: 0

Related Questions