2

I am trying to read a text file, sport.txt, which contains the following and am trying to match the user input with the sports name found in the text file.

If it's found it will print "sports found" and if it's not found it will print "No sports found".

The first example shown looks almost perfect till I tried to key in a random word and it displays an error:

[: ==: unary operator expected

I have also tried using the "" for the variable in the second example shown, but it will just print "No sports found" even though I typed an exact sports name matches with the sports name in the text file.

File sports.txt

cycling
swimming
batmintion

Code (example 1)

#!/bin/bash
file="sports.txt"
read -p "Enter a sports name": sportsName
existingSports=$(grep $sportsName $file);
if [ $existingSports == $sportsName ]; then
     echo "Sports Found"
else
     echo "No Sports Found"
fi

If I key in 'swimming' base on the above code, the output is:

Sports Found

Now if I key in 'swim', the output is:

No Sports Found

And if I key in a random word 'asd', the output is:

[: ==: unary operator expected
No Sports Found

Code (example 2)

#!/bin/bash
file="sports.txt"
read -p "Enter a sports name": sportsName
existingSports=$(grep $sportsName $file);
if [ "$existingSports" == "$sportsName" ]; then
     echo "Sports Found"
else
     echo "No Sports Found"
fi

If I key in 'swimming' base on the above codes, the output is:

No Sports Found

Now if I key in 'swim', the output is:

No Sports Found

Code (example 3)

#!/bin/bash
file="sports.txt"
read -p "Enter a sports name": sportsName
existingSports=$(grep $sportsName $file);
if [[ "$existingSports" == "$sportsName" ]]; then
     echo "Sports Found"
else
     echo "No Sports Found"
fi

If I key in 'swimming' base on the above code, the output is:

No Sports Found

Now if I key in 'swim', the output is:

No Sports Found

As mentioned, the first example is almost close to the expected. What should I do to get rid of the error message?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user3493435
  • 81
  • 1
  • 3
  • 11

2 Answers2

2

Try doing it in my way:

 #!/bin/bash
 file="sports.txt"
 read -p "Enter a sports name": sportsName
 sportsName=`echo $sportsName | sed -e 's/^ *//g' -e 's/ *$//g'`
 # The above sed command will remove all trailing and leading spaces which user can give as input
 result=`grep -c $sportsName $file`;
 if [ $result -eq 0 ]
 then
     echo "Sorry No match found"
 else

     echo "$result matches found"
 fi

"-c" in grep will count the number of occurrences and if the occurrence is not 0, it shows the number of occurrences in the else loop.

Remember using "`" tild sign on the grep command

If you are looking for exact word and not be be a substring of other word then use -w -c in the grep command:

result=`grep -w -c $sportsName $file`;

man entries for -w:

   -w, --word-regexp
      Select only those lines containing matches that form whole
      words. The test is that the matching substring must either
      be at the beginning of the line, or preceded by a non-word
      constituent character. Similarly, it must be either at the
      end of the line or followed by a non-word constituent
      character. Word-constituent characters are letters,
      digits, and the underscore.
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ashish
  • 1,856
  • 18
  • 30
  • you method works. but there's is also a slight problem to it. if you type a sports name e.g swim instead of swimming, it will still read it as match found. – user3493435 Oct 28 '13 at 09:16
  • 1
    then best is to use grep -w -c result=`grep -w -c $sportsName $file`; Actually -w will check exact word for you and not substring – Ashish Oct 28 '13 at 09:35
  • Oh dear. Terrible lacks of quotes and use of outdated backticks. This answer will break as soon as user inputs some spaces. Oh, and `if grep -q` is much better (especially if file is long). But why did this answer receive so many upvotes? – gniourf_gniourf Oct 28 '13 at 09:54
  • similarly sed -e 's/^ *//g' -e 's/ *$//g' can be used if you want to remove extra leading and trailing spaces of user input and then go for grep -w – Ashish Oct 28 '13 at 10:16
2

Instead of this block:

existingSports=$(grep $sportsName $file);
if [ $existingSports == $sportsName ]; then
     echo "Sports Found"
else 
     echo "No Sports Found"
fi

You can just utilize grep -q with word boundaries and reduce your code to single line:

grep -q "\<$sportsName\>" "$file" && echo "Sports Found" || echo "No Sports Found"

As per man grep:

-q, --quiet, --silent

Quiet; do not write anything to standard output. Exit immediately with zero status if any match is found, even if an error was detected.

anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 1
    Instead of using word boundaries, use `"^$sportsName\$"`. Otherwise, if file contains `horse-riding` and user inputs `riding` or `horse`, it will be counted as found. – gniourf_gniourf Oct 28 '13 at 09:57
  • 1
    We can remove the trailing and leading extra spaces (if user inputs some white spaces or spaces) using sed sed -e 's/^ *//g' -e 's/ *$//g' later we can go for grep -w -q for exact matching – Ashish Oct 28 '13 at 10:13
  • @Ashish: Yes `grep -wq` can also be used for matching exact word. – anubhava Oct 28 '13 at 10:17
  • yess But since user has its own logic in If and Else loop we can go with grep & then condition block if user input has to be precised with removing spaces "sportsName=`echo $sportsName | sed -e 's/^ *//g' -e 's/ *$//g'` " which will remove all extra spaces in user inputs – Ashish Oct 28 '13 at 10:22
  • 1
    @Ashish without `IFS=''`, read will automatically discard spaces at the beginning and end of user input, so your `sed` is really useless. Besides, `echo $sportsName` (with unquoted `$sportsName`) will automatically discard all spaces in at the beginning and end of user input, as well as replace any multiple spaces by a single one. Ah but there's a trap: if user's input starts with a hypen, you might have problems `:)` – gniourf_gniourf Oct 28 '13 at 11:54
  • 1
    @Ashish if you want to safely replace any multiple spaces by a single one, you could `read` in an array as `read -a sportsName_ary` and then `sportsName="${sportsName_ary[@]}"`. – gniourf_gniourf Oct 28 '13 at 11:58