0

My first parameter is the file that contains the given words and the rest are the other directories in which I'm searching for files, that contain at least 3 of the words from the 1st parameter

I can successfully print out the number of matching words, but when testing if it's greater then 3 it gives me the error: test: too many arguments

Here's my code:

#!/bin/bash

file=$1
shift 1

for i in $*
do
    for j in `find $i`
    do
        if test -f "$j"
        then
            if test grep -o -w "`cat $file`" $j | wc -w -ge 3
            then
                echo $j
            fi
        fi
    done


done
Róbert Nagy
  • 6,720
  • 26
  • 45

3 Answers3

1

You first need to execute the grep | wc, and then compare that output with 3. You need to change your if statement for that. Since you are already using the backquotes, you cannot nest them, so you can use the other syntax $(command), which is equivalent to `command`:

if [ $(grep -o -w "`cat $file`" $j | wc -w) -ge 3 ]
then
    echo $j
fi
kontiki
  • 37,663
  • 13
  • 111
  • 125
  • BTW: I did not checked the logic of your code, just the reason why you are getting the too many arguments error. – kontiki Apr 07 '17 at 17:12
1

I believe your problem is that you are trying to get the result of grep -o -w "cat $file" $j | wc -w to see if it's greater or equal to three, but your syntax is incorrect. Try this instead:

 if test $(grep -o -w "`cat $file`" $j | wc -w) -ge 3

By putting the grep & wc commands inside the $(), the shell executes those commands and uses the output rather than the text of the commands themselves. Consider this:

> cat words
western
found
better
remember

> echo "cat words | wc -w"
cat words | wc -w

> echo $(cat words | wc -w)
4

> echo "cat words | wc -w gives you $(cat words | wc -w)"
cat words | wc -w gives you 4

> 

Note that the $() syntax is equivalent to the double backtick notation you're already using for the cat $file command.

Hope this helps!

Roger Sinasohn
  • 483
  • 4
  • 11
1

Your code can be refactored and corrected at few places.

Have it this way:

#!/bin/bash

input="$1"
shift

for dir; do
    while IFS= read -r d '' file; do
         if [[ $(grep -woFf "$input" "$file" | sort -u | wc -l) -ge 3 ]]; then
             echo "$file"
         fi
    done < <(find "$dir" -type f -print0)
done
  • for dir loops through all the arguments
  • Use of sort -u is to remove duplicate words from output of grep.
  • Usewc -linstead ofwc -wsincegrep -o` prints matching words in separate lines.
  • find ... -print0 is to take care of file that may have whitespaces.
  • find ... -type f is to retrieve only files and avoid checking for -f later.
anubhava
  • 761,203
  • 64
  • 569
  • 643