Подсчитать количество вхождений подстроки в строку

Передать любой вывод команды в less и это позволит разбивать на страницы, искать и еще много чего.

ls -lA / etc | less

Поскольку ваш текст отображается с помощью 'less', нажмите h , чтобы получить помощь, прочтите и поразмышляйте. man less - больше читать.

5
08.05.2018, 17:14
6 ответов

Используя функции обработки строк, мы могли бы сделать это с помощью Perl следующим образом:

 printf '%s\n' "$STRING" |
 perl -nse '
      $_.= join "", <>;
      $k++ while ++($p = index($_, $s, $p));
      print $k, "\n" ;
 '    --     -s="$SUB_STRING" 

Пояснение:

° load up the whole string in $_

°  index function will return the position of a substring in a string OTW returns -1

° progressively match the substring and use the position found as the starting position for the next search. 

°  all this while increment the counter $k depicting substring found. 

Некоторые другие методы перечислены ниже:

Удалите строку и используйте регулярное выражение.

printf '%s\n' "$STRING" |
perl -slp -0777e '
        $_ = () = /$s/g;
 ' -- -s="$s" 

° Вставить строку в переменную $ _.

° передать подстроку из командной строки в perl с помощью опции -s.

° Теперь выполните сопоставление с $ _и в контексте списка получите совпадения, которые затем будут взяты в скалярном контексте для получения количества совпадений.

° опция -p автоматически печатает содержимое $ _.

Метод с использованием инструмента sed:

 esc_s=$(printf '%s\n' "$SUB_STRING" |\
 sed -e 's:[][\/.^$*]:\\&:g' -e 'H;1h;$!d;g;s/\n/\\n/g')

 printf '%s\n' "$STRING" |
 sed -ne '
         $!{N;s/^/\n/;D;}
         /'"$esc_s"'/{
               x;p;x
               s///;s/^/\n/;D
         }
 ' | wc -l

° В качестве подготовительного шага мы идем дальше и экранируем все символы, действующие как метасимволы, в левую часть оператора s/// в подстроке, что, если не сделать, приведет к сбою sed.

° Теперь мы вливаем всю строку в пространство шаблонов.

° затем мы продолжаем печатать пустую строку, место хранения является хорошим кандидатом, и удаляем подстроку из пространства шаблона.

° промыть... вспенить... повторять до тех пор, пока присутствует подстрока.

° Затем пустые строки передаются в инструмент wc, который дает нам количество строк = количество найденных подстрок.

Это версия оболочки:

 e=$STRING  N=0
 while 
     e=$(expr " $e" : " \(.*\)$SUB_STRING")
     case $e in "" ) break ;; esac
  do
           N=$(expr "$N" + 1)
  done
  echo "$N"
3
27.01.2020, 20:32

Если у вас есть gnugrep, вы можете запустить что-то вроде

grep -zPio 'Bluetooth\s+Soft blocked: no\s+Hard blocked: no' ex.txt | grep -zc.

1
27.01.2020, 20:32

Вы можете использовать Python, как в этом вопросе

python -c 'print "abcdabcva".count("ab")'

Или если вы работаете с переменными оболочки:

python -c 'print("""'"$STRING"'""".count("""'"$SUB_STRING"'"""))'

В вашем случае:

python -c 'print """0: asus-wlan: Wireless LAN
                   Soft blocked: no
                   Hard blocked: no
          1: asus-bluetooth: Bluetooth
                   Soft blocked: no
                   Hard blocked: no
          2: phy0: Wireless LAN
                   Soft blocked: no
                   Hard blocked: no
          113: hci0: Bluetooth
                   Soft blocked: no
                   Hard blocked: no""".count("""Bluetooth
                   Soft blocked: no
                   Hard blocked: no""")'
2
27.01.2020, 20:32
gawk '
END { print NR - 1 }
' RS='Bluetooth
         Soft blocked: no
         Hard blocked: no' input.txt

Пояснение

RS-разделитель входных записей, по умолчанию новая строка. Установите его на нужную строку, и awkразделит весь текст на записи, используя эту строку в качестве разделителя. Затем остается только вывести количество записей, вычтенных 1в секции END.

Использование переменных:

#!/bin/bash

STRING='0: asus-wlan: Wireless LAN
         Soft blocked: no
         Hard blocked: no
1: asus-bluetooth: Bluetooth
         Soft blocked: no
         Hard blocked: no
2: phy0: Wireless LAN
         Soft blocked: no
         Hard blocked: no
113: hci0: Bluetooth
         Soft blocked: no
         Hard blocked: no'

SUB_STRING='Bluetooth
         Soft blocked: no
         Hard blocked: no'

gawk 'END { print NR - 1 }' RS="$SUB_STRING" <<< "$STRING"
2
27.01.2020, 20:32

Сperl:

printf '%s' "$SUB_STRING" |
  perl -l -0777 -ne '
    BEGIN{$sub = <STDIN>}
    @matches = m/\Q$sub\E/g;
    print scalar @matches' <(printf '%s' "$STRING")

Только с bashвсегда можно сделать что-то вроде:

s=${STRING//"$SUB_STRING"}
echo "$(((${#STRING} - ${#s}) / ${#SUB_STRING}))"

То есть $sсодержит $STRINGсо всеми удаленными вхождениями $SUB_STRINGвнутри него. Мы находим количество $SUB_STRING, которые были удалены, вычисляя разницу в количестве символов между $STRINGи $sи деля на длину самого $SUB_STRING.

POSIXly вы могли бы сделать что-то вроде:

s=$STRING count=0
until
  t=${s#*"$SUB_STRING"}
  [ "$t" = "$s" ]
do
  count=$((count + 1))
  s=$t
done
echo "$count"
8
27.01.2020, 20:32

Если подстрока не содержит разрывов строк:

echo -n STRING | grep -Fo SUBSTRING | wc -l
3
08.11.2020, 02:15

Теги

Похожие вопросы