1

How can you match everything that doesn't match a pattern?

Trying with sed gives very awkward looking results.

If we want to replace this file:

The quick brown fox leaps over the lazy dog.  
The swift brown fox leaps over the lazy dog.  
The swift green frog leaps over the lazy fox.  
The quick yellow dog leaps over the lazy fox.  


with:

The quick brown fox jumps over the lazy dog.    
The swift brown fox jumps over the lazy dog.    
The quick yellow dog jumps over the lazy fox.    


What is an elegant way to do this?

Peter Brooks
  • 349
  • 3
  • 13

4 Answers4

4

You can just use a grep -Ev "regex pattern" /path/to/yout/file and it will match every line that does not match the regex pattern

Esteban
  • 1,752
  • 1
  • 8
  • 17
  • 2
    Note that the -E switch isn't essential. – Casimir et Hippolyte May 19 '17 at 09:38
  • 1
    @CasimiretHippolyte Yes, you're right, it was the habit to type this command as I tend to regularly use quantifiers and so I usualy type `grep -E` each time I use a regex even when not necessary ;) – Esteban May 19 '17 at 09:42
  • Yes, that's true. However, you can't, then, in the same line, make the changes you want to make. The reason I posted this, is that I was looking for the solution to this problem, and found a very complicated page here: http://stackoverflow.com/questions/406230/regular-expression-to-match-a-line-that-doesnt-contain-a-word - so I thought I'd provide an easier solution. – Peter Brooks May 19 '17 at 10:00
4

If you just want to print lines that don't match your regular expression, grep -v is the correct tool for the job.

You can do a simple replacement in sed on lines that don't match like this:

sed -n '/frog/! s/leaps/jumps/ p' file

-n means don't print, ! negates the match, s substitutes then p prints

For more complex processing, I'd use awk (I've showed the equivalent to the sed example here):

awk '!/frog/ { sub(/leaps/, "jumps"); print }' file
Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
  • Strangely, though, it doesn't work: It doesn't print anything. I've just tried it on linux, and OS/X. If doesn't print anything. Any suggestions? – Peter Brooks May 19 '17 at 11:16
2

Is it something like this you are looking for?

awk '!/green/{$5="jump"; print}' file

The quick brown fox jump over the lazy dog.
The swift brown fox jump over the lazy dog.
The quick yellow dog jump over the lazy fox.
Claes Wikner
  • 1,457
  • 1
  • 9
  • 8
-3

I would recommend using awk.

Your data is kept in 'input_file':

The quick brown fox leaps over the lazy dog.  
The swift brown fox leaps over the lazy dog.  
The swift green frog leaps over the lazy fox.  
The quick yellow dog leaps over the lazy fox.  


You want to match lines that don't match frog. Here is the awk script. Notice that we put the sed regular expression (regex) in the string cmd replace this with any sed regex you want (NB: You really do need the close(cmd)):

!/frog/  {cmd="echo " $0 "|sed 's/leaps/jumps/'" ;cmd|getline output;print output;close(cmd)}


Put the above into the script 'match_all_but_frog.awk'. Then:

awk -f match_all_but_frog.awk <input_file


output:

The quick brown fox jumps over the lazy dog.  
The swift brown fox jumps over the lazy dog.  
The quick yellow dog jumps over the lazy fox.  



If you want to match 'Frog','Frogs' or 'FROGS' as well as 'frog':

BEGIN {
IGNORECASE = 1;
      }
!/frog|frogs/  {cmd="echo " $0 "|sed 's/leaps/jumps/'" ;cmd|getline output;print output;close(cmd)}
Peter Brooks
  • 349
  • 3
  • 13
  • 1
    To match `frog` as well as `frogs` you don't need to use an alternation since the first branch (frog) matches also frogs. – Casimir et Hippolyte May 19 '17 at 09:49
  • 1
    It makes no sense at all to use this complicated approach, when you can just use `sub`/`gsub` to do substitutions in awk. To make an action block conditional on _not_ matching a regex, use `!/regex/`. – Tom Fenech May 19 '17 at 09:53
  • Yes, if you're used to using awk, I agree, there are lots of ways of doing this better. I was trying to provide something that could be used by somebody unfamiliar with awk who was having trouble doing this with sed. I was looking for this solution myself, and found a complicated page here, this was supposed to be easier: http://stackoverflow.com/questions/406230/regular-expression-to-match-a-line-that-doesnt-contain-a-word – Peter Brooks May 19 '17 at 10:03
  • Yes, it's true that 'frog' matches 'frogs' too. The point of doing that was to illustrate that you could put arbitrary regular expressions in there to not-match lots of things... rather than to look for frogs particularly. – Peter Brooks May 19 '17 at 10:05
  • Thank you for the suggestion, @tom-fenech, I've improved the answer by incorporating it. – Peter Brooks May 19 '17 at 10:10