144

Let's say I have a variable

line="This is where we select from a table."

now I want to grep how many times does select occur in the sentence.

grep -ci "select" $line

I tried that, but it did not work. I also tried

grep -ci "select" "$line"

It still doesn't work. I get the following error.

grep: This is where we select from a table.: No such file or directory
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
gkmohit
  • 3,309

3 Answers3

198

Have grep read on its standard input. There you go, using a pipe...

$ echo "$line" | grep select

... or a here string...

$ grep select <<< "$line"

Also, you might want to replace spaces by newlines before grepping :

$ echo "$line" | tr ' ' '\n' | grep select

... or you could ask grep to print the match only:

$ echo "$line" | grep -o select

This will allow you to get rid of the rest of the line when there's a match.

Edit: Oops, read a little too fast, thanks Marco. In order to count the occurences, just pipe any of these to wc(1) ;)

Another edit made after lzkata's comment, quoting $line when using echo.

John WH Smith
  • 15,880
  • 3
    Since the OP wants to count the number of occurrences of a string you can add a wc to complete the task: grep -o <string> <<< "$variable" | wc -l – Marco Oct 23 '14 at 15:39
  • 4
    Use echo "$line" to preserve existing newlines instead of creating ones with tr – Izkata Oct 23 '14 at 16:31
  • What is the availability of a Here String? Does it require Bash or another shell? –  Jan 24 '16 at 20:43
  • 1
    According to Wikipedia, here strings are available in bash, ksh, and zsh (but I'm assuming there may be others). – John WH Smith Jan 24 '16 at 21:17
  • i don't understand how bash question indexing is so bad, answers do not answer the question, how to do:

    myoutput | grep -v $SOMEVAR

    condition itself is a variable.

    – Aubergine May 23 '20 at 00:14
  • 1
    @Aubergine: copy-pastable examples - Filter-string is a variable: seq 4 | grep -v $SHLVL ; Filter-string from a different process: seq 4 | grep -v "$(seq 2)" Or seq 4 | grep -vf <(seq 2) ; Input from a different process: grep -v $SHLVL <(seq 4) Or grep -v $SHLVL <<< "$(seq 4)" – Amit Naidu Jun 03 '20 at 23:20
10
test=$line i=0
while case "$test" in (*select*)
test=${test#*select};;(*) ! :;;
esac; do i=$(($i+1)); done

You don't need to call grep for such a simple thing.

Or as a function:

occur() while case "$1" in (*"$2"*) set -- \
        "${1#*"$2"}" "$2" "${3:-0}" "$((${4:-0}+1))";;
        (*) return "$((${4:-0}<${3:-1}))";;esac
        do : "${_occur:+$((_occur=$4))}";done

It takes 2 or 3 args. Providing any more than that will skew its results. You can use it like:

_occur=0; occur ... . 2 && echo "count: $_occur"

...which prints the occurrence count of . in ... if it occurs at least 2 times. Like this:

count: 3

If $_occur is either empty or unset when it is invoked then it will affect no shell variables at all and return 1 if "$2" occurs in "$1" fewer than "$3" times. Or, if called with only two args, it will return 1 only if "$2" is not in "$1". Else it returns 0.

And so, in its simplest form, you can do:

occur '' . && echo yay || echo shite

...which prints...

shite

...but...

occur . . && echo yay || echo shite

...will print...

yay

You might also write it a little differently and omit the quotes around $2 in both the (*"$2"*) and "${1#*"$2"}" statement. If you do that then you can use shell globs for matches like sh[io]te for the match test.

mikeserv
  • 58,310
1

I would just use sed to break up the sentence for me and then compare each line in a loop because this seems like the easiest way to me (no offence to anyone here, and also I am not an expert so there may be a reason people don't do it this way, not sure)

string="a a a a a asd gsam en"
count=$(echo $string | sed 's/ /\n/g' | grep -w 'a' | wc -l)
echo $count

when I run it

mark@gamerblock:~$ string="a a a a a asd gsam en"
mark@gamerblock:~$ count=$(echo $string | sed 's/ /\n/g' | grep -w 'a' | wc -l)
mark@gamerblock:~$ echo $count
5

As a script with input argument

#!/bin/bash
echo "Enter your string"
read string
echo "Enter what you want substring counted"
read substring
count=$(echo $string | sed 's/ /\n/g' | grep $substring | wc -l)
echo $count

when ran

mark@gamerblock:~$ ./substring.sh
Enter your string
peter piper picked a pack of pickled peppers. a pack of pickled peppers peter piper did pick.
Enter what you want substring counted
peter
2
mark@gamerblock:~$ ./substring.sh
Enter your string
peter piper picked a pack of pickled peppers. a pack of pickled peppers peter piper did pick.
Enter what you want substring counted
p
0

If you don't want exact matches, remove the -w argument from grep

mark@gamerblock:~$ ./substring.sh
Enter your string
peter piper picked a pack of pickled peppers. a pack of pickled peppers peter piper did pick.
Enter what you want substring counted
p
12
mark@gamerblock:~$
  • 1
    This looks a lot like John WH Smith’s answer. OK, you’ve added grep -w, but you haven’t explained what that does. – G-Man Says 'Reinstate Monica' Jul 01 '22 at 02:46
  • The difference between my answer an Mr. Smith's is that the OP asked for how many matches in a sentence/string, and, to the best of my knowledge, the method using grep (as the OP requested) does not break the sentence into individual lines so that grep can go through it (which is why I used sed). Then wc -l was added to count the number of lines after the regex "select" was matched. The -w on grep makes it only match whole-word results, so something like "selection" won't trigger the filter – MarkTheRusty Jul 03 '22 at 00:23
  • Sorry, upon re-reading, I didn't see the 'tr' command with grep initially. So the only difference in my answer and Mr. Smith's is the use of sed – MarkTheRusty Jul 03 '22 at 00:26
  • There's too many 'e's in argument (twice) – Greenonline Jul 08 '22 at 19:24
  • Fixed, thanks Greenonline! – MarkTheRusty Jul 14 '22 at 02:58