> 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
    grep -f $line $regex
    grep -lr "${line%.js}" . | tee -a ~/Documents/counter/output2.txt           # produce a list of occurrences


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, 2015 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 Aug 12, 2015 at 19:02
  • The brackets are for range selection Aug 12, 2015 at 19:02
  • @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, 2015 at 19:27

2 Answers 2


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


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"
  • 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? Aug 12, 2015 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. Aug 12, 2015 at 20:07

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .