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"
Jericob
fonte

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}'
hek2mgl
fonte
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"
jm666
fonte
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.

Robin Hsu
fonte
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

rmanna
fonte
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}"
user2508516
fonte
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

Mathew PV
fonte
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
Freeman
fonte