4

I have a script written in bash, with one particular grep command I need to modify.

Generally I have two patterns: A & B. There is a textfile that can contain lines with all possible combinations of those patterns, that is: "xxxAxxx", "xxxBxxx", "xxxAxxxBxxx", "xxxxxx", where "x" are any characters.

I need to match ALL lines APART FROM the ones containing ONLY "A".

At the moment, it is done with "grep -v (A)", but this is a false track, as this would exclude also lines with "xxxAxxxBxxx" - which are OK for me. This is why it needs modification. :)

The tricky part is that this one grep lies in the middle of a 'multiply-piped' command with many other greps, seds and awks inside. Thus forming a smarter pattern would be the best solution. Others would cause much additional work on changing other commands there, and even would impact another parts of the code.

Therefore, the question is: is there a possibility to match pattern and exclude a subpattern in one grep, but allow them to appear both in one line?

Example: A file contains those lines:

fooTHISfoo
fooTHISfooTHATfoo
fooTHATfoo
foofoo

and I need to match

fooTHISfooTHATfoo
fooTHATfoo
foofoo

a line with "THIS" is not allowed.

ptr92zet
  • 163
  • 9

4 Answers4

3

You can use this awk command:

awk '!(/THIS/ && !/THAT/)' file
fooTHISfooTHATfoo
fooTHATfoo
foofoo

Or by reversing the boolean expression:

awk '!/THIS/ || /THAT/' file
fooTHISfooTHATfoo
fooTHATfoo
foofoo
anubhava
  • 664,788
  • 59
  • 469
  • 547
  • 1
    Actually I didn't notice that my case could be written as a boolean expression... Solution worked perfectly, thank you very much. – ptr92zet Sep 25 '15 at 11:32
2

You want to match lines that contain B, or don't contain A. Equivalently, to delete lines containing A and not B. You could do this in sed:

sed -e '/A/{;/B/!d}'

Or in this particular case:

sed '/THIS/{/THAT/!d}' file
hek2mgl
  • 133,888
  • 21
  • 210
  • 235
Toby Speight
  • 23,550
  • 47
  • 57
  • 84
1

Tricky for grep alone. However, replace that with an awk call: Filter out lines with "A" unless there is a "B"

echo "xxxAxxx
xxxBxxx
xxxAxxxBxxx
xxxBxxxAxxx
xxxxxx" | awk '!/A/ || /B/'
xxxBxxx
xxxAxxxBxxx
xxxBxxxAxxx
xxxxxx
glenn jackman
  • 207,528
  • 33
  • 187
  • 305
1

grep solution. Uses perl regexp (-P) for Lookaheads (look if there is not, some explanation here).

grep -Pv '^((?!THAT).)*THIS((?!THAT).)*$' file
Community
  • 1
  • 1
pacholik
  • 7,596
  • 8
  • 43
  • 50