Выбор подстроки внутри строки в bash - PullRequest
1 голос
/ 14 апреля 2020

Я совершенно новичок в сценариях оболочки и пытаюсь извлечь подстроку внутри строки, которую вводит пользователь. У меня есть файл a.txt, который содержит:

abc.com
div.abc.com

Теперь, если пользователь вводит www.abc.com, я хочу выбрать abc.com из этого файла и поместить abc.com в переменную. и если пользователь вводит prod.div.abc.com, тогда я хочу выбрать div.abc.com из этого файла и поместить div.abc.com в переменную.

Я пытаюсь использовать:

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

Кажется вывод далек от моих ожиданий.

Ответы [ 3 ]

1 голос
/ 14 апреля 2020

Используя ассоциативный массив Bash4, более эффективно хранить файл доменов a.txt в качестве ключей ассоциативного массива (или ключей словаря).

#!/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

Позволяет проверить его

Заполнить a.txt:

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

Запустить сценарий, используя CTRL + d , чтобы остановить:

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

0 голосов
/ 14 апреля 2020

Я предполагаю, что read предназначен для получения пользовательского ввода, в то время как a.txt имеет список шаблонов для сопоставления:

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

Варианты grep:

  • -F - сопоставить фиксированные строки
  • -o - вывести только совпадающую часть
  • -f a.txt - прочитать шаблоны (фиксированные строки) из файла a.txt
0 голосов
/ 14 апреля 2020

Вы можете попробовать захватить ввод от пользователя, используя read, а затем использовать grep для поиска совпадения.

#!/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
  • Это предполагает, что ваш файл имеет одну запись на -line.

  • Если есть совпадение, оно будет в "$var"

  • Оба входа могут иметь ведущий prod. и www.

...