1

I have this data:

##sequence-region Q75T13 1 641
Q75T13,UniProtKB,Chain,1,641,.,.,.,ID
Q75T13,UniProtKB,Topological domain,1,60,.,.,.,Note=Cytoplasmic
Q75T13,UniProtKB,Transmembrane,61,85,.,.,.,Note=Helical
Q75T13,UniProtKB,Topological domain,86,641,.,.,.,Note=Lumenal


##sequence-region Q9BRR3 1 403
Q9BRR3,UniProtKB,Chain,1,403,.,.,.,ID
Q9BRR3,UniProtKB,Topological domain,1,22,.,.,.,Note=Lumenal
Q9BRR3,UniProtKB,Transmembrane,23,43,.,.,.,Note=Helical
Q9BRR3,UniProtKB,Topological domain,44,259,.,.,.,Note=Cytoplasmic

##sequence-region Q96FM1 1 250
Q96FM1,UniProtKB,Topological domain,120,135,.,.,.,Note=Cytoplasmic
Q96FM1,UniProtKB,Transmembrane,136,156,.,.,.,Note=Helical
Q96FM1,UniProtKB,Topological domain,157,169,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Transmembrane,170,190,.,.,.,Note=Helical
Q96FM1,UniProtKB,Topological domain,191,250,.,.,.,Note=Lumenal

And I was wondering what the awk code would look like for:

The rows that have the word lumenal, if in the previous row it has the word transmembrane, subtract -12 in column 4 and print the row with the word lumenal. If the row with the word lumenal has the word "transmembrane" in the next row, add +12 in column 5 and print the row with the word lumenal. The final file would be:

Q75T13,UniProtKB,Topological domain,74,641,.,.,.,Note=Lumenal
Q9BRR3,UniProtKB,Topological domain,1,34,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,145,169,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,157,181,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,179,250,.,.,.,Note=Lumenal

Can someone help me? I am a little bit stuck. I am trying with awk and grep

3
  • Not easy to do. Because the column separator is not clear. You use space to separate columns, but the third column also has space, like "Topological domain". May 2, 2022 at 16:30
  • I don't know why, but all the column separators should be tabs. I have tried to change it. Check it now if it's okay May 2, 2022 at 16:35
  • I have change it to a csv, now I suppose that would be easier :) May 2, 2022 at 16:41

3 Answers 3

3

Try the following command:

root@u2004:~# cat test
##sequence-region Q75T13 1 641
Q75T13,UniProtKB,Chain,1,641,.,.,.,ID
Q75T13,UniProtKB,Topological domain,1,60,.,.,.,Note=Cytoplasmic
Q75T13,UniProtKB,Transmembrane,61,85,.,.,.,Note=Helical
Q75T13,UniProtKB,Topological domain,86,641,.,.,.,Note=Lumenal


##sequence-region Q9BRR3 1 403
Q9BRR3,UniProtKB,Chain,1,403,.,.,.,ID
Q9BRR3,UniProtKB,Topological domain,1,22,.,.,.,Note=Lumenal
Q9BRR3,UniProtKB,Transmembrane,23,43,.,.,.,Note=Helical
Q9BRR3,UniProtKB,Topological domain,44,259,.,.,.,Note=Cytoplasmic

##sequence-region Q96FM1 1 250
Q96FM1,UniProtKB,Topological domain,120,135,.,.,.,Note=Cytoplasmic
Q96FM1,UniProtKB,Transmembrane,136,156,.,.,.,Note=Helical
Q96FM1,UniProtKB,Topological domain,157,169,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Transmembrane,170,190,.,.,.,Note=Helical
Q96FM1,UniProtKB,Topological domain,191,250,.,.,.,Note=Lumenal
root@u2004:~# 
root@u2004:~# awk -F, -v OFS=, '{while(1){if($0~/Lumenal/){a=$0; $4-=12;p=$0; $0=a;$5+=12;n=$0; if(index(pre,"Transmembrane")>0)print p; if(getline>0){if(index($0,"Transmembrane"))print n; if($0~/Lumenal/){pre=$0; continue}}} break}} {pre=$0}' test
Q75T13,UniProtKB,Topological domain,74,641,.,.,.,Note=Lumenal
Q9BRR3,UniProtKB,Topological domain,1,34,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,145,169,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,157,181,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,179,250,.,.,.,Note=Lumenal
root@u2004:~#
12
  • Thank you so much! It seems to work perfectly May 2, 2022 at 16:58
  • @RafaelSolerOrtuño No problem. Why not give me an upvote? I need more upvotes! May 2, 2022 at 17:04
  • 2
    @EdMorton Thank you for the correction! I'm new to awk and I'll read the doc. May 2, 2022 at 23:07
  • 2
    @EdMorton Is it possible to modify my command (still in one liner) so that it produces correct result? I'm not able to delete this accepted answer. May 2, 2022 at 23:09
  • 2
    Lol, that's correct😅. I'm trying to fix my answer. Thanks for the link. You are a real awk guru, I noticed your name in the article, and it's from 2006! May 2, 2022 at 23:40
2

Just keep a rolling buffer of 3 lines and examine that:

$ cat tst.awk
BEGIN { FS=OFS="," }
{
    nxt = $0
    prt()
}
END {
    prt()
}

function prt() {
    if ( cur ~ /Lumenal/ ) {
        if ( pre ~ /Transmembrane/ ) {
            $0 = cur
            $4 -= 12
            print
        }

        if ( nxt ~ /Transmembrane/ ) {
            $0 = cur
            $5 += 12
            print
        }
    }

    pre = cur
    cur = nxt
    nxt = ""
}

$ awk -f tst.awk file
Q75T13,UniProtKB,Topological domain,74,641,.,.,.,Note=Lumenal
Q9BRR3,UniProtKB,Topological domain,1,34,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,145,169,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,157,181,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,179,250,.,.,.,Note=Lumenal
3
  • That's an amazing answer Mr Morton. Can I ask you other thing? I am trying to do a similar thing: - Find the rows with the word "lumenal", and if there is a row with the word transmembrane before, do the subtraction of the columns $5 and $4 of the previous row, and subtract it from the column $4 of the row with the word lumenal - Find the rows with the word "lumenal", and if there is a row after that, do the subtraction of the columns $5 and $4 of the previous row with the word transmembrane, and add it to column $5 of the row with the word lumenal. May 3, 2022 at 8:31
  • I am trying to do $5 += $5-$4, but it gives me the rest of the lumenal row, how can I store the transmembrane susbtract and calculate the operation after? Thank you so much! May 3, 2022 at 8:35
  • I'm sorry, I'm not sure I fully understand what you're asking. Please just ask a new question, don't ask additional questions in comments where you can't provide formatted sample input/output that demonstrate your requirements.
    – Ed Morton
    May 3, 2022 at 13:10
2

I worked this one out before you changed the column separators to commas. First job was to change the multiple spaces to tabs in my test file:

$ cat indata 
##sequence-region Q75T13 1 641
Q75T13  UniProtKB   Chain   1   641 .   .   .   ID
Q75T13  UniProtKB   Topological domain  1   60  .   .   .   Note=Cytoplasmic    
Q75T13  UniProtKB   Transmembrane   61  85  .   .   .   Note=Helical
Q75T13  UniProtKB   Topological domain  86  641 .   .   .   Note=Lumenal


##sequence-region Q9BRR3 1 403
Q9BRR3  UniProtKB   Chain   1   403 .   .   .   ID
Q9BRR3  UniProtKB   Topological domain  1   22  .   .   .   Note=Lumenal
Q9BRR3  UniProtKB   Transmembrane   23  43  .   .   .   Note=Helical
Q9BRR3  UniProtKB   Topological domain  44  259 .   .   .   Note=Cytoplasmic

##sequence-region Q96FM1 1 250
Q96FM1  UniProtKB   Topological domain  120 135 .   .   .   Note=Cytoplasmic
Q96FM1  UniProtKB   Transmembrane   136 156 .   .   .   Note=Helical
Q96FM1  UniProtKB   Topological domain  157 169 .   .   .   Note=Lumenal
Q96FM1  UniProtKB   Transmembrane   170 190 .   .   .   Note=Helical
Q96FM1  UniProtKB   Topological domain  191 250 .   .   .   Note=Lumenal

Next the script. Note that the third argument in the split functions is a tab.

#!/bin/bash
awk '
        function add12(out_line) {
                iarr = split( out_line, arr, "  " )
                arr[5] = 12 + arr[5]
                printf( "%s", arr[1])
                for (i=2 ; i<=iarr ; i++) printf( "\t%s", arr[i] )
                printf( "\n" )
        }

        function sub12(out_line) {
                iarr = split( out_line, arr, "  " )
                arr[4] = arr[4] - 12
                printf( "%s", arr[1])
                for (i=2 ; i<=iarr ; i++) printf( "\t%s", arr[i] )
                printf( "\n" )
        }

        NR == 1 { last_line = $0 ; next }
        NR == 2 { test_line = $0 ; next }

        test_line ~ /Lumenal/ {
                if (last_line ~ /Transmembrane/) sub12( test_line )
                if ($0  ~ /Transmembrane/) add12( test_line )
        }

        {
                last_line = test_line
                test_line = $0
        }

        END {
                if (test_line ~ /Lumenal/) {
                        if (last_line ~ /Transmembrane/) sub12( test_line )
                }
        }
' $1

and the "proof of the pudding":

$ ./doit indata
Q75T13  UniProtKB   Topological domain  74  641 .   .   .   Note=Lumenal
Q9BRR3  UniProtKB   Topological domain  1   34  .   .   .   Note=Lumenal
Q96FM1  UniProtKB   Topological domain  145 169 .   .   .   Note=Lumenal
Q96FM1  UniProtKB   Topological domain  157 181 .   .   .   Note=Lumenal
Q96FM1  UniProtKB   Topological domain  179 250 .   .   .   Note=Lumenal

I've created doit2:

$ diff doit*
4c4
<       iarr = split( out_line, arr, "  " )
---
>       iarr = split( out_line, arr, "," )
7c7
<       for (i=2 ; i<=iarr ; i++) printf( "\t%s", arr[i] )
---
>       for (i=2 ; i<=iarr ; i++) printf( ",%s", arr[i] )
12c12
<       iarr = split( out_line, arr, "  " )
---
>       iarr = split( out_line, arr, "," )
15c15
<       for (i=2 ; i<=iarr ; i++) printf( "\t%s", arr[i] )
---
>       for (i=2 ; i<=iarr ; i++) printf( ",%s", arr[i] )

and used the csv file:

$ ./doit2 comma
Q75T13,UniProtKB,Topological domain,74,641,.,.,.,Note=Lumenal
Q9BRR3,UniProtKB,Topological domain,1,34,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,145,169,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,157,181,.,.,.,Note=Lumenal
Q96FM1,UniProtKB,Topological domain,179,250,.,.,.,Note=Lumenal
1
  • Thank you for your answer Martin, I have asked another question to Ed which I am struggling, in case you have and idea. May 3, 2022 at 8:59

You must log in to answer this question.

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