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"
Jericob
fuente
unix.stackexchange.com/questions/18736/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

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

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

rmanna
fuente
2

awk funciona bien si tu servidor lo tiene

var="text,text,text,text" 
num=$(echo "${var}" | awk -F, '{print NF-1}')
echo "${num}"
user2508516
fuente
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

Mathew PV
fuente
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
Hombre libre
fuente