Count occurrences of a char in a string using Bash

BashShellSh

Bash Problem Overview


I need to count the number of occurrences of a char in a string using Bash.

In the following example, when the char is (for example) t, it echos the correct number of occurrences of t in var, but when the character is comma or semicolon, it prints out zero:

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

Bash Solutions


Solution 1 - Bash

you can for example remove all other chars and count the whats remains, like:

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

will print

,,,
3

or

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

or

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

or

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

or

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

or

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

Solution 2 - Bash

I would use the following awk command:

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

I'm splitting the string by $char and print the number of resulting fields minus 1.

If your shell does not support the <<< operator, use echo:

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

Solution 3 - Bash

You can do it by combining tr and wc commands. For example, to count e in the string referee

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

output

4

Explanations: Command tr -cd 'e' removes all characters other than 'e', and Command wc -c counts the remaining characters.

Multiple lines of input are also good for this solution, like command cat mytext.txt | tr -cd 'e' | wc -c can counts e in the file mytext.txt, even thought the file may contain many lines.

*** Update ***

To solve the multiple spaces in from of the number (@tom10271), simply append a piped tr command:

 tr -d ' '

For example:

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

Solution 4 - Bash

Building on everyone's great answers and comments, this is the shortest and sweetest version:

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

Solution 5 - Bash

awk is very cool, but why not keep it simple?

num=$(echo $var | grep -o "," | wc -l)

Solution 6 - Bash

awk works well if you your server has it

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

Solution 7 - Bash

I Would suggest the following:

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

No call to any other program

Solution 8 - Bash

also check this out, for example we wanna count t

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

or in python

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

or even better, we can make our script dynamic with awk

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

in this case output is like this :

e 1
s 1
t 2

Solution 9 - Bash

The awk solutions provided here so far all break if there's a line break in your text. E.g.:

text="one,two,thr
ee,four"
DELIM=','
count=$( awk -F"$DELIM" '{print NF-1}' <<<"${text}" )
echo $count

Result:

2
1

The solution that will also work correctly with line breaks is:

text="one,two,thr
ee,four"
DELIM=','
count=$( awk 'BEGIN{RS="'"$DELIM"'";FS=""}END{print NR-1}' <<<"${text}" )
echo $count

Result is 3.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJericobView Question on Stackoverflow
Solution 1 - Bashjm666View Answer on Stackoverflow
Solution 2 - Bashhek2mglView Answer on Stackoverflow
Solution 3 - BashRobin HsuView Answer on Stackoverflow
Solution 4 - BashrmannaView Answer on Stackoverflow
Solution 5 - BashMatthew SnyderView Answer on Stackoverflow
Solution 6 - Bashuser2508516View Answer on Stackoverflow
Solution 7 - BashMathew P VView Answer on Stackoverflow
Solution 8 - BashFreemanView Answer on Stackoverflow
Solution 9 - BashMeckiView Answer on Stackoverflow