1
> output2.txt
cd # some directory i'm trying to search
find views/shared -type f -name "*.js" -print0 | while IFS= read -r -d $'\0' line; do
    echo -n "${line%.js}" | tee -a ~/Documents/counter/output2.txt
    grep -lr "${line%.js}" . | wc -l | tee -a ~/Documents/counter/output2.txt   # produce a count of occurrences
    regex='[a-zA-Z]+.extend'
    grep -f $line $regex
    grep -lr "${line%.js}" . | tee -a ~/Documents/counter/output2.txt           # produce a list of occurrences
done

Returns

grep: brackets ([ ]) not balanced

All the examples I've seen on the web seem to indicate there is nothing wrong here, so i'm pretty confused

Surely the square brackets are balanced, aren't they?

  • 1
    What are you trying to achieve? what is in your file referenced by $line variable? By default grep needs to escape brackets to take into effect, unless you use extended grep – Jakuje Aug 12 '15 at 18:59
  • I put the full command. I'm grepping through a BackboneJS code base and looking for the phrase "*.extends" to find parent classes – itsmichaelwang Aug 12 '15 at 19:02
  • The brackets are for range selection – itsmichaelwang Aug 12 '15 at 19:02
  • 2
    I don't think -f does what you think it does. It reads patterns to search for from the file, it doesn't grep that file. – drewbenn Aug 12 '15 at 19:04
  • @drewbenn is right. You are using -f wrongly. And from your code is still not much obvious what you want to achieve. – Jakuje Aug 12 '15 at 19:27
1

Your issue is the -f option. Instead of specifying the file to search, -f specifies a file to read a list of patterns from. OS X grep's man page explains it, though not very clearly:

 -f file, --file=file
         Read one or more newline separated patterns from file.  Empty pattern lines match every input
         line.  Newlines are not considered part of a pattern.  If file is empty, nothing is matched.

The help for GNU grep is actually more straightforward:

$ grep --help | grep -- '-f,'
  -f, --file=FILE           obtain PATTERN from FILE
$ 

This behavior of -f is, according to GNU grep's man page, specified by POSIX.

Your fix is probably to change your line:

grep -f $line $regex

to:

egrep "$regex" -- "$line"
  • You are using an extended regular expression so use egrep or grep -E
  • The -- will prevent grep from parsing any options in the $line variable, e.g. it would protect you against a file named "-r funnyname.js"
  • (and FWIW, I'd get rid of find altogether, turn on shopt -s globstar and loop on for line in **/*.js, but that's just my personal code-readability preference and isn't necessarily faster/better). – drewbenn Aug 12 '15 at 19:36
  • So I'm not actually getting anything now... I want to search for the file's contents, and $line is the filename I believe. Is there a way to do that? – itsmichaelwang Aug 12 '15 at 20:05
  • Actually I should probably clarify. I want to find this line: return BaseView.extend({ Everything is telling me the regex should be a match, but grep returns nothing. – itsmichaelwang Aug 12 '15 at 20:07
  • @Zapurdead grep -E since you want extended regexps. – drewbenn Aug 12 '15 at 20:16
0

If the input going into the grep pipe contains square brackets ('[' and ']'), grep will have a hard time handling them gracefully. You must first "sanitize" the input by using something like this to encase each square bracket in a pair of square brackets, thereby causing them to be interpreted as literal characters to be matched:

CommandYouWantToPipeThroughGREP | sed -e 's^\([][]\)^\[\1\]^g' | grep ...

Explanation of sed command:

sed -e: an expression follows the -e. It must be encased in single or double quotes.

s^: [s]earch for. "^" is being used as a field delimiter. Every time you see "^", it's delimiting a new part of the search option.

\(...\) and \1: escaped parentheses encase a pattern that you want to be able to access as a variable in sed. The first such pattern is referred to as "\1"; the second is "\2", and so on.

[][]: The outer two brackets are encasing the inner two. The first character after a "[" is automatically assumed to be literal (escaped/having no special meaning). Since that first character is a bracket, the next bracket is also assumed to be literal, unless it's the only bracket before the end of that "^"-delimited field. (At least, that's my understanding of how it works...)

\[\1\]: Encase sed variable 1 ("\1") in literal brackets, and send it to output.

g: [g]reedy. It means, "Find and replace all examples of the search text, instead of just the first one".

So, just pipe any input that might contain square brackets through this sed command before piping it through grep, and grep will look for the the brackets literally, instead of interpreting them as special characters. Unfortunately, it would seem that, if you pipe to ANOTHER grep command, after the first one, you need to run it through sed, again, to re-escape the brackets.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.