Contar ocorrências de um caractere em uma string usando o Bash


123

Preciso contar o número de ocorrências de um caractere em uma string usando o Bash.

No exemplo a seguir, quando o caractere é (por exemplo) t, echoé o número correto de ocorrências de tin var, mas quando o caractere é vírgula ou ponto e vírgula, ele imprime zero:

var = "text,text,text,text" 
num = `expr match $var [,]`
echo "$num"

Respostas:


118

Eu usaria o seguinte awkcomando:

string="text,text,text,text"
char=","
awk -F"${char}" '{print NF-1}' <<< "${string}"

Estou dividindo a string $chare imprima o número de campos resultantes menos 1.

Se o seu shell não suportar o <<<operador, use echo:

echo "${string}" | awk -F"${char}" '{print NF-1}'

5
@HattrickNZ Então use:$(grep -o "$needle" < filename | wc -l)
hek2mgl

13
@Amir O que você espera?
hek2mgl

3
Você pode pular o wc -l, basta usar grep -c, ele funciona tanto em bsd grep quanto em linux grep.
andsens 5/08/16

8
@andsens grep -cproduzirá apenas o número de linhas correspondentes. Não conta várias correspondências por linha.
precisa saber é o seguinte

1
Eu quero contar '$' s em uma string, como posso escapar '$' da string principal?
6/18

117

você pode, por exemplo, remover todos os outros caracteres e contar o que resta, como:

var="text,text,text,text"
res="${var//[^,]}"
echo "$res"
echo "${#res}"

irá imprimir

,,,
3

ou

tr -dc ',' <<<"$var" | awk '{ print length; }'

ou

tr -dc ',' <<<"$var" | wc -c    #works, but i don't like wc.. ;)

ou

awk -F, '{print NF-1}' <<<"$var"

ou

grep -o ',' <<<"$var" | grep -c .

ou

perl -nle 'print s/,//g' <<<"$var"

1
um pouco mais de truque aqui como #y="${x//[^s|S]}"; echo "${#y}"
Aquarius Power

4
use o primeiro, sempre evite recorrer à geração de outro processo para fazer um trabalho como esse, pois pode afetar seriamente o desempenho ao usar com loops de iteração grandes. Como regra geral, a execução de processos externos deve ser o último recurso ao usar operações de iteração ou repetição.
osirisgothra

Por que você não gosta wc? Golfe!
Ciro Santilli escreveu

1
@CiroSantilli六四事件法轮功包卓轩porque por exemploecho -n some line | wc -l
jm666

O bloco de código 4 é o melhor na minha opinião. Precisamos facilitar a obtenção de:tr -dc ',' <<<"$var" | wc -c
bgStack15

68

Você pode fazer isso combinando tre wccomandos. Por exemplo, para contar ena sequência referee

echo "referee" | tr -cd 'e' | wc -c

resultado

4

Explicações: O comando tr -cd 'e'remove todos os caracteres, exceto 'e', ​​e o comando wc -cconta os caracteres restantes.

Várias linhas de entrada também são boas para esta solução, como comando cat mytext.txt | tr -cd 'e' | wc -cpode contar eno arquivo mytext.txt, mesmo que o arquivo contenha muitas linhas.


3
Sua solução parece ser a mais limpa e fácil de lembrar, obrigado!
jirislav

Isso é ótimo. Obrigado!
Kodie Grantham

Eu amo isso, porque eu odeio awk!
franzisk

3

Com base nas ótimas respostas e comentários de todos, esta é a versão mais curta e agradável:

grep -o "$needle" <<< "$haystack" | wc -l


2

O awk funciona bem se você tiver seu servidor

var="text,text,text,text" 
num=$(echo "${var}" | awk -F, '{print NF-1}')
echo "${num}"

Apenas como uma nota: awk -F,procura um ,. Você pode fazer o seguinte:awk -F"${your_char}"
Emixam23

1

Eu sugeriria o seguinte:

var="any given string"
N=${#var}
G=${var//g/}
G=${#G}
(( G = N - G ))
echo "$G"

Nenhuma chamada para outro programa


1

também verifique isso, por exemplo, queremos contar t

echo "test" | awk -v RS='t' 'END{print NR-1}'

ou em python

python -c 'print "this is for test".count("t")'

ou melhor ainda, podemos tornar nosso script dinâmico com awk

echo 'test' | awk '{for (i=1 ; i<=NF ; i++) array[$i]++ } END{ for (char in array) print char,array[char]}' FS=""

neste caso, a saída é assim:

e 1
s 1
t 2
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.