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"