문자열에서 하위 문자열의 발생 횟수를 계산합니다.

문자열에서 하위 문자열의 발생 횟수를 계산합니다.

Bash를 사용하여 문자열에서 하위 문자열의 발생 횟수를 계산하는 방법은 무엇입니까?

예:

이 하위 문자열이 몇 번이나 나타나는지 알고 싶습니다.

Bluetooth
         Soft blocked: no
         Hard blocked: no

...이 문자열에 나타납니다...

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

참고 1:sed, grep, awk 등을 사용하여 다양한 방법을 시도했습니다. 공백과 여러 줄이 포함된 문자열이 있으면 아무것도 작동하지 않는 것 같습니다.

노트 2:저는 Linux 사용자이고 Linux 배포판에서 일반적으로 발견되는 것 이외의 앱/도구를 설치하지 않는 솔루션을 시도하고 있습니다.


중요한:

나는 아래의 가상의 예와 같은 것을 원합니다. 이 예에서는 두 가지를 사용합니다.셸 변수(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"

awk -v RS='\0' 'NR==FNR{str=$0; next} {print gsub(str,"")}' "$STRING" "$SUB_STRING"

노트:우리는 설명을 위해서만 awk를 사용합니다!

답변1

그리고 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"

답변2

하위 문자열에 개행 문자가 포함되어 있지 않은 경우:

echo -n STRING | grep -Fo SUBSTRING | wc -l

답변3

문자열 처리 기능을 사용하면 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" 

° 문자열을 $_ 변수에 넣습니다.

° -s 옵션을 사용하여 명령줄에서 Perl로 하위 문자열을 전달합니다.

° 이제 $_에 대해 일치를 수행하고 목록 컨텍스트에서 일치 항목을 가져온 다음 스칼라 컨텍스트에서 일치 항목을 가져와 일치 항목 수를 가져옵니다.

° -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"

답변4

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"

관련 정보