I have a file with several different lines. I'm looking for lines that contain(more or less) pattern like this:


In other words, I want the lines that have <something> between []. Examples might be:

Line with [ <matching>|<pattern>]
A line <that> does[not]<match>[]
But [this[<should>]be matched] too
[match [me] <buddy>]

The only characters allowed between <> are alphanumeric characters and underscore.

I've tried both regexp above and its lazy version, but it didn't seem to work. What is the proper regexp?

  • How about line [with <foo]bar> or line [with <foo]bar> baz] or a [b <c[d]e> f]? – Stéphane Chazelas Aug 27 '15 at 13:20
  • @StéphaneChazelas I've updated my question to answer yours. – MatthewRock Aug 27 '15 at 13:23

If your [, ] pairs are always matched and you don't criss-cross [...]s with <...>, and your grep supports the -P option (like GNU grep when built with PCRE support), you can do:

grep -P '>(?!((?:[^]]|\[(?1)\])*)$)'

That is, look for a > that is not followed by only matched [...] pairs. It uses PCREs' (?1) recursive matching mechanism.

  • Outstanding. Works like a charm. – MatthewRock Aug 27 '15 at 13:50

POSIXly, you could do it with sed:

sed  '
  h; # make a copy of the pristine line on the hold space
      # found a [...<x>...]
      g; # retrieve our saved copy and branch off
    s/\[\([^]]*\)]/\1/g; # remove inner [...]s
    # and loop if that s command was successful
  # no [...] left to remove, discard this line.

That is, remove pairs of [...] starting from the inner ones until you find a <...> within a pair.

(on Solaris or very old systems, remove the comments as Solaris sed only allows comments at the start of the lines).


This pattern with lazy matching (needing -P AFAIU) works for me:

grep -P '\[[^\]]*?<.*>.*?\]'

I came up with the following solution:

grep -P '\[[^.\]]*<.*>[^.\[]*\]' filename

In other words we match a pair of [ and ] with a pair of < and > in between with the following constraints:

  1. between [] must not be closing and opening bracket accordingly before and after the <> pair "[^.\]]*".
  2. inside <> must be at least one character.

This solution is also much faster than the regex with lazy quantifiers.

  • Unfortunately fails for [a [b] <c>] – MatthewRock Aug 27 '15 at 13:12

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.