michaelmeyer
michaelmeyer

Reputation: 8205

Count the number of occurrences of a pattern in a string (with bash builtins only)

I have a string which looks like this:

STRING="$PATTERN_some-stuff_$PATTERN_some-other_stuff"

I would like to count the number of occurences of $PATTERN in it, only with Bash builtin commands.

The more straightforward way of doing this I have found so far is to extract from the string only the strings that match $PATTERN, and then to count how many occurrences of $PATTERN there are in the newly created string, proceeding this way:

expr length "${STRING//[^$PATTERN]}" / ${#PATTERN}

But it only works if $PATTERN is a single character. I tried to use the syntax ${STRING//!(PATTERN)}", which would, if I understand well Bash manual, only match $PATTERN at the exclusion of the rest of $STRING, but it actually outputs nothing. So, where am I wrong ?

Upvotes: 3

Views: 5125

Answers (2)

glenn jackman
glenn jackman

Reputation: 246807

If you're a bit flexible about builtins only, this is a perfect situation for grep -o:

$ STRING='$PATTERN_some-stuff_$PATTERN_some-other_stuff'
$ grep -o '$PATTERN' <<< "$STRING" | wc -l
2

Upvotes: 6

iruvar
iruvar

Reputation: 23364

One option is to replace all instances of PATTERN in STRING, subtract the length of this shortened string from the length of STRING, and then divide this by length of PATTERN. And by the way, you have flouted your bash built-in requirement by using expr. expr is a command(at least on my Ubuntu server)

$ declare -- PATTERN="abracadabra"
$ declare -- STRING="${PATTERN}_some-stuff_${PATTERN}_some-other_stuff"
$ echo $STRING
abracadabra_some-stuff_abracadabra_some-other_stuff
$ temp=${STRING//$PATTERN}
$ string_length_without_patterns=${#temp}
$ total_pattern_length=$((${#STRING} - $string_length_without_patterns))
$ number_of_patterns=$(($total_pattern_length/${#PATTERN}))
$ echo $number_of_patterns
2

Upvotes: 2

Related Questions