2

I have a file which looks like this

a   0   gene1   56  0   6S32M12S    *
b   256 gene2   56  0   6S32M12S    *
c   256 gene3   55  0   6S27M17S    *
d   16  gene4   110 9   19S25M6S    *
e   272 gene5   141 9   23S21M6S    *
f   272 gene6   139 9   24S20M6S    *
g   0   gene7   38  1   6S44M   *
h   256 gene8   38  1   6S44M   *
I   256 gene9   38  1   6S44M   *
j   256 gene10  40  1   8S42M   *

The 6th column is the string I want to filter on. Basically if the string contains a match equal to or more than 16S(so let's say 16S,17S,18S,19S and more) than report those lines. How can I do that? The out put for the above example would be:

c   256 gene3   55  0   6S27M17S    *
d   16  gene4   110 9   19S25M6S    *
e   272 gene5   141 9   23S21M6S    *
f   272 gene6   139 9   24S20M6S    *

I just showed you a little snippet from a big file.

  • Does the second S count? – muru Jan 6 '15 at 18:17
  • 1
    So now you have * around the text or is that a formatting error? – muru Jan 6 '15 at 19:17
  • Thats a formatting error. Fixed it.. – user3138373 Jan 6 '15 at 19:42
5
perl -ane 'print if grep {$_ >= 16} ($F[5] =~ /(\d+)S/g)' file

outputs

c   256 gene3   55  0   6S27M17S    *
d   16  gene4   110 9   19S25M6S    *
e   272 gene5   141 9   23S21M6S    *
f   272 gene6   139 9   24S20M6S    *

That finds all the digits followed by "S" in the 6th field. If any are greater than or equal to 16, it prints the line.


Look for -n in perldoc perlrun

One cool way to see what perl is doing with a one-liner is to add the option -MO=Deparse

$ perl -MO=Deparse -ane 'print if grep {$_ >= 16} ($F[5] =~ /(\d+)S/g)'
LINE: while (defined($_ = <ARGV>)) {
    our(@F) = split(' ', $_, 0);
    print $_ if grep {$_ >= 16;} $F[5] =~ /(\d+)S/g;
}
-e syntax OK

see
http://perldoc.perl.org/B/Deparse.html
http://perldoc.perl.org/O.html

I'll explain by expanding the one-liner into a script:

#!/usr/bin/env perl
my $filename = shift @ARGV;
open my $fh, '<', $filename or die $!;
while (defined($_ = <$fh>)) {
    my @F = split(' ', $_, 0);
    my @s_numbers = $F[5] =~ /(\d+)S/g;
    if (grep {$_ >= 16;} @s_numbers) {
        print $_;
    }
}
close $fh;
  • Hi glenn, This works perfectly. Can you explain what you did here. For some reason I can easily understand perl in the script form but not on command line. If you could explain the code , it would be really nice. Thanks – user3138373 Jan 6 '15 at 19:30
1

Assuming the second S also matters:

awk '{
split ($6, nums, /S([0-9]+M)?/); 
for (i in nums) 
  if (nums[i] > 16) 
    { print; next }
}' test.txt
  • Hi muru, The code isn't working. Also I changed the input file a bit since I encountered this thing now. Please have a look. Help!!! – user3138373 Jan 6 '15 at 19:16
  • @user3138373 try the second code. – muru Jan 6 '15 at 19:24

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.