Bash: Counting Occurrences of a Character in a String

To count the number of occurrences of a character (letter, digit, symbol) in a string in a bash script, you can use grep and wc:

grep -o `/` <<< $string |wc -l

In this example

  • $string - an arbitrary string
  • / - the delimiter

This symbiosis is very handy if you need to process a list made up of lines of arbitrary length with the same type of delimiter, and you need to cut one or two words out of that list.

If you need to cut out the 5th column in a line, or every fifth field after the delimiter — it’s very easy to do with the cut or awk utilities.

For example, say we have this set of lines combined into a list:

list=`'asd|fgh|jkl  
qwe|rty|uio  
zxc|vbn|nm<`'

Print the second element of each line:

for f in $list; do echo $f |awk -F`|` '{print $2}';done

or

for f in $list; do echo $f |cut -d `|` -f 2;done

As a result, we get:

fgh  
rty  
vbn

That’s all fine, but what if the lines have different lengths and we need to print the last element of each line?

For this example I’ll use the following list:

list=`'asd|fgh|jkl|123  
qwe|rty|uio|p[]|<?.|456  
zxc|vbn|789`'

We need to get the numbers.

In this case there are two tricks:

  1. Use sed to add one more delimiter to the end of each line and cut out the second-to-last element
  2. Use bc to add 1 to the count of occurrences and display that element.

First option:

for f in $list;
do
  echo $f |cut -d "|" -f $(echo $f |sed 's/$/\|/g' |grep -o "|" |wc -l)
done

In the example:
echo $f |sed 's/$/\|/g' |grep -o "|" |wc -l - does it all at once: adds | to the end of the line and counts the number of occurrences.

Second option:

for f in $list;
do
  echo $f |cut -d "|" -f $(bc <<< $(grep -o "|" <<< $f |wc -l)+1);
done

In the example:

  • grep -o "|" <<< $f |wc -l - counts the number of occurrences of the “ ” delimiter in each line
  • bc <<< $(grep ...)+1 - adds one

Categories:

Updated: