BASH - conte o número de ocorrências de uma substring em uma string

0

Como posso contar o número de ocorrências de uma substring em uma string usando o Bash?

EXEMPLO:

Gostaria de saber quantas vezes essa substring ...

Bluetooth
         Soft blocked: no
         Hard blocked: no

... ocorre nesta cadeia ...

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

NOTA I: Tentei várias abordagens com sed, grep, awk ... Nada parece funcionar quando temos strings com espaços e várias linhas.

NOTA II: Eu sou um usuário Linux e estou tentando uma solução que não envolve a instalação de aplicativos / ferramentas fora daqueles que normalmente são encontrados nas distribuições Linux.


IMPORTANTE:

Eu gostaria de algo como o exemplo hipotético abaixo. Nesse caso, usamos duas variáveis ​​de shell (Bash) .

EXEMPLO:

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"

NOTA: Estamos usando o awk apenas para ilustrar!

Eduardo Lucio
fonte
Você provavelmente encontrará mais ajuda no Stack Overflow, o site SE para programadores. Você também pode encontrar mais ajuda no Unix e Linux SE.
JúniorRubyist

Respostas:

2

Suponho que isso possa ser melhorado awk, mas é o melhor que posso oferecer.

grep -zo "Bluetooth\s*Soft blocked: no\s*Hard blocked: no" file_name | grep -c "Bluetooth"

-zfaz greptratar o arquivo inteiro como uma linha.

-ograva apenas a saída que corresponde à string e não à linha inteira.
(no nosso caso, com -zisso significa o arquivo inteiro)

\s corresponde a caracteres em branco e novas linhas.

A segunda instância de greppesquisará apenas a palavra "Bluetooth" na saída da primeira grepchamada.

-cfaz grepescrever a contagem de regex correspondente, em vez de corresponder a si próprio.

Iskustvo
fonte
Muito obrigado @Iskustvo, mas acho que há um problema na sua resposta. Temos que escapar da string que modifica a quantidade de espaços e, além disso, precisaríamos ter alguma funcionalidade para automatizar esse processo. Fora isso, eu gostaria de poder usar variáveis ​​Shell (Bash) (veja a modificação e minha pergunta)! Vou tentar explicar melhor. Por exemplo, AFAIK se minha entrada for "Soft bloqueado: não" ou "Soft bloqueado: não" com o valor "\ s * Soft bloqueado: não" o resultado da correspondência se tornará indiferente aos espaços da string original inserida. Obrigado! = D
Eduardo Lucio
2
Entendo o que você está dizendo, bem, não tudo, mas a maioria. No entanto, acho que não sou capaz de fornecer uma resposta melhor. Sua solicitação excede as ferramentas grep e sed e é necessário usar algo como awk, perl ou python e não posso ajudá-lo com isso. Espero que outra resposta atenda a todos os seus critérios.
Iskustvo
Muito obrigado pela sua contribuição! Desculpe pelo meu inglês ruim (na verdade eu falo português)! = D
Eduardo Lucio
0

Não está claro como você gostaria de corresponder (seu exemplo adicional no comentário acima não lança nenhuma luz), no entanto, suponha que você armazene seu bloco de strings com as informações de rede dentro de um arquivo stringe o bloco de substring dentro de um arquivo substring.

Usando a seguinte abordagem, você obteria o que eu entendo que você esperava: 2 correspondências.

cat string | tr -s " " | tr '\n' '@' | grep -o "$(cat substring | tr -s " " | tr '\n' '@')" | wc -l

Essencialmente, as duas seqüências são condensadas em uma linha, ignorando espaços em branco ou tabulações e convertendo novas linhas em @. Usando a grep -osintaxe, imprimimos todas as ocorrências ( -o) do padrão encontrado.

No entanto, não está claro se, no seu exemplo, você espera que ele corresponda a 0 vezes (correspondência posicional exata) ou 2 vezes (ignorando o texto anexado). Esta é uma solução muito semelhante à que Iskustvo postou aqui ; será que não entendemos sua intenção?

Se você estiver tentando contar correspondências de um fragmento de texto bidimensional, provavelmente precisará de grep difuso.

Moreaki
fonte