Compter les occurrences d'un caractère dans une chaîne à l'aide de Bash

123

J'ai besoin de compter le nombre d'occurrences d'un caractère dans une chaîne en utilisant Bash.

Dans l'exemple suivant, lorsque le caractère est (par exemple) t, il echoest le nombre exact d'occurrences tdans var, mais quand le caractère est une virgule ou point - virgule, il affiche zéro:

var = "text,text,text,text" 
num = `expr match $var [,]`
echo "$num"
Jericob
la source
unix.stackexchange.com/questions/18736/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:

118

J'utiliserais la awkcommande suivante :

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

Je divise la chaîne par $charet j'imprime le nombre de champs résultants moins 1.

Si votre shell ne prend pas en charge l' <<<opérateur, utilisez echo:

echo "${string}" | awk -F"${char}" '{print NF-1}'
hek2mgl
la source
5
@HattrickNZ Ensuite, utilisez:$(grep -o "$needle" < filename | wc -l)
hek2mgl
13
@Amir À quoi vous attendez-vous?
hek2mgl
3
Vous pouvez sauter le wc -l, utilisez simplement grep -c, il fonctionne à la fois sur bsd grep et linux grep.
andsens
8
@andsens grep -caffichera uniquement le nombre de lignes correspondantes. Il ne compte pas plusieurs correspondances par ligne.
hek2mgl
1
Je veux compter les '$' dans une chaîne, comment puis-je échapper '$' à la chaîne principale?
masT
118

vous pouvez par exemple supprimer tous les autres caractères et compter ce qui reste, comme:

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

va imprimer

,,,
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
la source
1
un autre truc ici commey="${x//[^s|S]}"; echo "${#y}"
Aquarius Power
4
utilisez le premier, vous devez toujours éviter de recourir à un autre processus pour effectuer un travail comme celui-ci, cela peut avoir un impact important sur les performances lors de l'utilisation avec de grandes boucles d'itération. En règle générale, l'exécution d'un processus externe doit être le dernier recours lors de l'utilisation d'opérations itératives ou répétées.
osirisgothra
Pourquoi tu n'aimes pas wc? Il joue au golf!
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
@CiroSantilli 六四 事件 法轮功 包 卓 轩 parce que par exempleecho -n some line | wc -l
jm666
Le bloc de code 4 est le meilleur à mon avis. Nous devons faciliter l'accès à:tr -dc ',' <<<"$var" | wc -c
bgStack15
68

Vous pouvez le faire en combinant tret des wccommandes. Par exemple, pour compter edans la chaîne referee

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

production

4

Explications: La commande tr -cd 'e'supprime tous les caractères autres que «e» et la commande wc -ccompte les caractères restants.

Plusieurs lignes d'entrée sont également bonnes pour cette solution, comme la commande cat mytext.txt | tr -cd 'e' | wc -cpeut compter edans le fichier mytext.txt, même si le fichier peut contenir plusieurs lignes.

Robin Hsu
la source
3
Votre solution semble être la plus propre et la plus facile à retenir, merci!
jirislav
C'est bien. Je vous remercie!
Kodie Grantham
J'adore ça, parce que je déteste awk!
franzisk
3

S'appuyant sur les bonnes réponses et commentaires de chacun, c'est la version la plus courte et la plus douce:

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

rmanna
la source
2

awk fonctionne bien si votre serveur l'a

var="text,text,text,text" 
num=$(echo "${var}" | awk -F, '{print NF-1}')
echo "${num}"
user2508516
la source
Juste une note: awk -F,recherche un fichier ,. Vous pouvez faire ce qui suit:awk -F"${your_char}"
Emixam23
1

Je suggérerais ce qui suit:

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

Aucun appel à aucun autre programme

Mathew PV
la source
1

Vérifiez également ceci, par exemple nous voulons compter t

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

ou dans python

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

ou mieux encore, nous pouvons rendre notre script dynamique avec awk

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

dans ce cas, la sortie est comme ceci:

e 1
s 1
t 2
Homme libre
la source