1

I'm trying to remove a four line block from a text file if the second line matches the Regex N+. The text file is composed of many repeating 4 line formats, ie:

@HEADER1
ACTGCNNNT
+
583@#!NMY
@HEADER2
ANNTGCGGG
+
4123N@!&*

The first line of the four block pattern will always start with @, however @ can appear anywhere in the fourth line as well, and since the pattern I'm looking for, N+ can also appear in the fourth line, I can't simply grep for N+.

Any ideas would be much appreciated :)

0

2 Answers 2

2
sed -ne:n -e's/\n/&/3;tp'  \
          -e'$!{N;bn' -e\} \
     -e:p -e'/\n.*N.*\n/p' \
<in >out

If your input occurs in regular blocks of four lines per, and if you're looking for at least one N that doesn't occur on the last of these four, then the above bit of sed should suit your needs. It does assume that your entire input file will be blocked off on four-line groups. If this is not the case just let me know and I can make it a little less presumptuous.

Anyway, first sed gathers 4 input lines - or pulls in input lines until 3 \newline delimiters are found in pattern space - and next it looks for an N which does not occur on either the first or last of the 4 lines just gathered. If it finds it, it prints the four-line group, else nothing is printed and the next cycle will begin with the next 4-line group.

But apparently, you're trying to remove the block in question. In that case:

sed -e'$!N;/\n.*N/{$!N;$!N;d' -e'};n;n' <in >out

...will do the trick. It first appends the Next input line to pattern space, then checks for an N which occurs on the second line of a 4-line block, and, if one is found, sed pulls in two more lines on any line which is !not the $last before deleting the entire block. If the second line didn't match N, it overwrites pattern space twice with the next input line - auto-printing as it does - and autoprints the last of these as well.

You might also use the first bit of sed and just do /\n.*N.*\n/!p instead of p for the last address, too, of course. That may be advantageous in that you can more easily alter it by switching the 3 there to any other number of lines per block which might interest you.

4
  • Is this case sensitive? My input only has N, not n (also what was the difference between the two posts (before and after editing) Jul 16, 2015 at 18:31
  • @LynneSmith - I just wrote an explanation about the second one. Where either N or n do not occur within an / address / it is because they are the sed commands for append Next input line to pattern space and overwrite pattern space with the next input line, and so are not relevant to the N match.
    – mikeserv
    Jul 16, 2015 at 18:35
  • Also, why in 4 input lines does it pull lines until 3 \n are found? The fourth line is included in the block that is removed, right? Jul 16, 2015 at 18:38
  • @LynneSmith - Yes, the \n is appended to the current line, and precedes that pulled in. So: printf %s\\n 1 2 3 4 | sed 'N;N;N;l;d will print: 1\n2\n3\n4 - all 4 lines are in pattern space, but only 3 delimiters are present - because the \newline occurs between input lines in pattern space.
    – mikeserv
    Jul 16, 2015 at 18:41
-1

Perl to the rescue!

Save as remove-blocks.pl, run as perl remove-blocks.pl input_file > output_file.

#!/usr/bin/perl
use strict;
use warnings;

my @four_lines;                      # Buffer to hold a block.
while (<>) {                         # Read the input line by line.
    if (@four_lines < 3) {           # Not reading the last line?
        push @four_lines, $_;        # Save it to the buffer.

    } else {
        print @four_lines, $_ if $four_lines[1] !~ /N+/;
        undef @four_lines;           # Clear the buffer.
    }
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .