Reputation: 13
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
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
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
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
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