1

I need to remove the lines corresponding to first 7 occurrences of a string from a txt file in a pattern range (string1-string2).

Example of txt file content:

whatever
xpto string1 foo2
whatever1 
string2
xpto1 another_foo
xpto string2

string2 foo1

whatever
string2 another_xpto
string2 string2
foo xpto string2 whatever 
anything else foo string2
xpto
string2
foo whatever

I need a solution with sed ranges, something like that:

sed '/string1/,/string2/d' file.txt

The point is that I don't know how to extend /string2/ until the line corresponding to seventh match of string2. The desirable output should be:

whatever
anything else foo string2
xpto
string2
foo whatever
2
  • 1
    Read stackoverflow.com/questions/65621325/… to understand why this matters and then change the word "pattern" to either "string" or "regexp" everywhere it occurs in your question so we can best answer it. Note that /string/ makes no sense since / is the regexp delimiter, not the string delimiter " - you either meant /regexp/ or index($0,"string") (the latter being if you use awk since sed doesn't have any support for string matching). – Ed Morton Jan 17 at 23:53
  • If any of the answers you got helped you then see unix.stackexchange.com/help/someone-answers for what to do next. – Ed Morton Jan 20 at 4:20
4
sed -e:t -e'/string1/!b' -e'/\(.*string2\)\{7\}/d;N;bt'
1
  • 3
    welcome back mikeserv – iruvar Jan 17 at 3:05
3
awk '/string1/{c=7}; c<1; {c-=gsub(/string2/, "&")}' file

c is initially 0, and set to 7 if string1 is found. The line is printed whenever c<1.

The gsub function returns the number of times string2 appears on each line. The counter c is decremented by that value.

0
1

Here's one way to do what you want using literal strings:

$ cat tst.awk
BEGIN { lgth = length(end) }
index($0,beg) { inBlock = 1 }
inBlock {
    rec = $0
    while ( pos = index(rec,end) ) {
        if ( ++cnt >= min ) {
            inBlock = 0
        }
        rec = substr(rec,pos+lgth)
    }
    next
}
{ print }

$ awk -v beg='string1' -v end='string2' -v min=7 -f tst.awk file
whatever
anything else foo string2
xpto
string2
foo whatever

The above will interpret backslashes in the strings (e.g. \t would become a tab), if that's an issue let me know as it's an easy workaround, e.g. using ENVIRON[].

0

Perl

perl -ne '
  if (my $e = /string1/ ... s/string2/$&/g >= 7) {
      $_ .= $e =~ /E0/ ? next : <>, redo;
  }
  print;
' file

Posix sed:

sed -ne '
  /string1/!{p;d;}
  :loop
    n
    /string2/H
    g;s//&/7;t
  b loop
' file

Output:

whatever
anything else foo string2
xpto
string2
foo whatever

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.