672

I need something like:

grep ^"unwanted_word"XXXXXXXX
1
  • 2
    grep -Rv "word_to_be_ignored" . | grep "word_to_be_searched" Commented Jun 20, 2018 at 9:26

9 Answers 9

1139

You can do it using -v (for --invert-match) option of grep as:

grep -v "unwanted_word" file | grep XXXXXXXX

grep -v "unwanted_word" file will filter the lines that have the unwanted_word and grep XXXXXXXX will list only lines with pattern XXXXXXXX.

EDIT:

From your comment it looks like you want to list all lines without the unwanted_word. In that case all you need is:

grep -v 'unwanted_word' file
7
  • 2
    what if I want to exclude N lines after the line with "unwanted word" as well? -v 'unwanted_word' --after N doesn't help because it INCLUDES the line and N lines after. Commented Nov 6, 2014 at 5:01
  • 1
    -v or --invert-match select non-matching lines. In your case grep -v 'unwanted_word' file or grep --invert-match 'unwanted_word' file. Commented Nov 29, 2016 at 7:10
  • I want to ignore one line above and one line below with matching pattern then How can i achieve it? Commented Dec 20, 2016 at 10:38
  • 4
    Weird, it's the top answer, but in some cases it's wrong! If I want to find sun, except when it is sunrise, grep sun|grep -v sunrise skips line that contain both sun and sunrise at once, that is not what I want. grep -P 'sun(?!rise)' is much better.
    – greene
    Commented Mar 24, 2018 at 10:05
  • 1
    If you want to bring the regex power into the exclude pattern, just add -E. e.g. grep -v -E "unwanted_pattern_in_regex" file
    – allenyllee
    Commented Sep 28, 2018 at 4:03
132

I understood the question as "How do I match a word but exclude another", for which one solution is two greps in series: First grep finding the wanted "word1", second grep excluding "word2":

grep "word1" | grep -v "word2"

In my case: I need to differentiate between "plot" and "#plot" which grep's "word" option won't do ("#" not being a alphanumerical).

4
  • 27
    You should reverse the order to get highlighting on word1. Commented Jun 16, 2015 at 20:45
  • 2
    I guess it would clarify to add a placeholder for the file name to that example
    – patrick
    Commented Aug 11, 2018 at 21:57
  • @MatthewRead I find it really more logic like this. First you're looking for occurences of "word1" then remove occurences found where there is also "word2" The opposite is strange : first removing "word2" and then looking the word you want. Maybe it's just a point of view
    – Nico
    Commented Apr 7, 2021 at 22:19
  • @Nico There's no reason to continue sticking to you initial impulse after finding something more useful, though. If you use this a lot, I would recommend creating a shell function that you can call (like xnoty() { grep -v "$2" | grep "$1" }) so you don't have to remember the construction. Commented Apr 8, 2021 at 16:16
48

If your grep supports Perl regular expression with -P option you can do (if bash; if tcsh you'll need to escape the !):

grep -P '(?!.*unwanted_word)keyword' file

Demo:

$ cat file
foo1
foo2
foo3
foo4
bar
baz

Let us now list all foo except foo3

$ grep -P '(?!.*foo3)foo' file
foo1
foo2
foo4
$ 
5
  • Thanks for this, very useful! I would like to mention that The grep command is case sensitive by default
    – DocWiki
    Commented Jul 16, 2011 at 17:49
  • 3
    Note that grep -v -P also works without negation in regular expression.
    – cybersoft
    Commented Oct 29, 2015 at 9:23
  • "if bash...you'll need to escape the !". Thank you thank you thank you! That's what I wanted! Commented Apr 19, 2020 at 6:55
  • However, this doesn't work in a way of `grep -P '(?!.*foo3)[a-zA-Z0-9]*' pattern, it won't find what you want to omit, but will find only the exact thing, so regexp is little useless for an exact phrases
    – FantomX1
    Commented Oct 22, 2020 at 14:19
  • 1
    The proposed pattern (?!.*unwanted_word)keyword only excludes lines where the unwanted_word starts after the keyword (possibly overlapped). To exclude any line that contains the unwanted_word, regardless of its position relative to the keyword, use ^(?!.*unwanted_word).*\Kkeyword .
    – Maëlan
    Commented Jan 16, 2022 at 18:15
47

The right solution is to use grep -v "word" file, with its awk equivalent:

awk '!/word/' file

However, if you happen to have a more complex situation in which you want, say, XXX to appear and YYY not to appear, then awk comes handy instead of piping several greps:

awk '/XXX/ && !/YYY/' file
#    ^^^^^    ^^^^^^
# I want it      |
#            I don't want it

You can even say something more complex. For example: I want those lines containing either XXX or YYY, but not ZZZ:

awk '(/XXX/ || /YYY/) && !/ZZZ/' file

etc.

2
  • 2
    It appears to be much faster than the grep -P solution on big files.
    – MBR
    Commented May 13, 2016 at 15:15
  • @MBR grep -P means using Perl regexp, so loading that package is going to be way more expensive than a normal grep.
    – fedorqui
    Commented May 14, 2016 at 22:28
13

Invert match using grep -v:

grep -v "unwanted word" file pattern
7

grep provides '-v' or '--invert-match' option to select non-matching lines.

e.g.

grep -v 'unwanted_pattern' file_name

This will output all the lines from file file_name, which does not have 'unwanted_pattern'.

If you are searching the pattern in multiple files inside a folder, you can use the recursive search option as follows

grep -r 'wanted_pattern' * | grep -v 'unwanted_pattern'

Here grep will try to list all the occurrences of 'wanted_pattern' in all the files from within currently directory and pass it to second grep to filter out the 'unwanted_pattern'. '|' - pipe will tell shell to connect the standard output of left program (grep -r 'wanted_pattern' *) to standard input of right program (grep -v 'unwanted_pattern').

5

The -v option will show you all the lines that don't match the pattern.

grep -v ^unwanted_word
0

I excluded the root ("/") mount point by using grep -vw "^/".

# cat /tmp/topfsfind.txt| head -4 |awk '{print $NF}'
/
/root/.m2
/root
/var

# cat /tmp/topfsfind.txt| head -4 |awk '{print $NF}' | grep -vw "^/"
/root/.m2
/root
/var
-4

I've a directory with a bunch of files. I want to find all the files that DO NOT contain the string "speedup" so I successfully used the following command:

grep -iL speedup *
1
  • 1
    From the man page: "-L, --files-without-match Suppress normal output; instead print the name of each input file from which no output would normally have been printed. The scanning will stop on the first match." (Emphasis by me) So beware of this!
    – xuiqzy
    Commented Jun 7, 2016 at 22:45

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