Contar las ocurrencias de un personaje en una cadena usando Bash


123

Necesito contar la cantidad de ocurrencias de un char en una cadena usando Bash.

En el siguiente ejemplo, cuando el carácter es (por ejemplo) t, echoes el número correcto de ocurrencias de tin var, pero cuando el carácter es coma o punto y coma, imprime cero:

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

Respuestas:


118

Usaría el siguiente awkcomando:

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

Estoy dividiendo la cadena $chare imprimo el número de campos resultantes menos 1.

Si su shell no es compatible con el <<<operador, use echo:

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

55
@HattrickNZ Luego use:$(grep -o "$needle" < filename | wc -l)
hek2mgl

13
@Amir ¿Qué esperas?
hek2mgl

3
Puede omitir el wc -l, solo use grep -c, funciona tanto en bsd grep como en linux grep.
andsens

8
@andsens grep -csolo generará el número de líneas coincidentes. No cuenta múltiples coincidencias por línea.
hek2mgl

1
Quiero contar '$' en una cadena, ¿cómo puedo escapar de '$' de la cadena principal?
masT

117

Puede, por ejemplo, eliminar todos los otros caracteres y contar los restos, como:

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

imprimirá

,,,
3

o

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

o

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

o

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

o

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

o

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

1
algún truco más aquí comoy="${x//[^s|S]}"; echo "${#y}"
Acuario de energía

44
use el primero, siempre debe evitar recurrir a generar otro proceso para hacer un trabajo como este, puede afectar gravemente el rendimiento cuando se usa con bucles de iteración grandes. Como regla, la ejecución de procesos externos debe ser el último recurso cuando se utilizan operaciones iterativas o repetitivas.
osirisgothra

¿Por qué no te gusta wc? ¡Golfs!
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

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

El bloque de código 4 es el mejor en mi opinión. Tenemos que hacer que sea más fácil llegar a:tr -dc ',' <<<"$var" | wc -c
bgStack15

68

Puedes hacerlo combinando try wccomandos. Por ejemplo, para contar een la cadena referee

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

salida

4

Explicaciones: Command tr -cd 'e'elimina todos los caracteres que no sean 'e', ​​y Command wc -ccuenta los caracteres restantes.

Varias líneas de entrada también son buenas para esta solución, como el comando cat mytext.txt | tr -cd 'e' | wc -cpuede contar een el archivo mytext.txt, incluso si el archivo puede contener muchas líneas.


3
Su solución parece ser la más limpia y fácil de recordar, ¡gracias!
jirislav

Esto es genial. ¡Gracias!
Kodie Grantham

¡Amo esto, porque odio awk!
franzisk

3

Basándose en las excelentes respuestas y comentarios de todos, esta es la versión más corta y dulce:

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


2

awk funciona bien si tu servidor lo tiene

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

Solo como una nota: awk -F,busca a ,. Puede hacer lo siguiente:awk -F"${your_char}"
Emixam23

1

Sugeriría lo siguiente:

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

No llame a ningún otro programa


1

también mira esto, por ejemplo queremos contar t

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

o en python

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

o incluso mejor, podemos hacer que nuestro script sea dinámico con awk

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

en este caso la salida es así:

e 1
s 1
t 2
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.