Move new line character 5 positions downstream in a text (fasta) file

Viewed 60

I am trying to transform a text file like this (fasta format):

>seq1
AAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAA
ATGATGATGGAATGAGGAT
TTAGGAGGGAGGAAAATTC
>seq2
CCCTCCGGGAAAAAAGAGG
TTGCAATGCGCGTATTTAT
TTTTTTTTTTTTTTTTTTT
AAAAAAAAAAAAAGGCTGT
AAAAAAAAAAAAAAAGGGG

The objective is to displace newline character 5 positions downstream, except for those lines starting with >

>seq1
AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAATGATGATGGAATGA
GGATTTAGGAGGGAGGAAAATTC
>seq2
CCCTCCGGGAAAAAAGAGGTTGCA
ATGCGCGTATTTATTTTTTTTTTT
TTTTTTTTTAAAAAAAAAAAAAGG
CTGTAAAAAAAAAAAAAAAGGGG

I would like to use AWK, but I am not sure how to proceed. I am thinking about something similar to this:

awk '{for(i=1;i<=NR;i++){ if($1 ~ /^>/){¿?¿?¿?}}}'

Do you know how can I solve this?

4 Answers

I would do it following way, let file.txt content be

>seq1
AAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAA
ATGATGATGGAATGAGGAT
TTAGGAGGGAGGAAAATTC
>seq2
CCCTCCGGGAAAAAAGAGG
TTGCAATGCGCGTATTTAT
TTTTTTTTTTTTTTTTTTT
AAAAAAAAAAAAAGGCTGT
AAAAAAAAAAAAAAAGGGG

then

awk 'BEGIN{width=24}/>/&&x{print x;x=""}/>/{print;next}{x = x $0}length(x)>=width{print substr(x,1,width);x=substr(x,width+1)}END{print x}' file.txt

gives output

>seq1
AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAATGATGATGGAATGA
GGATTTAGGAGGGAGGAAAATTC
>seq2
CCCTCCGGGAAAAAAGAGGTTGCA
ATGCGCGTATTTATTTTTTTTTTT
TTTTTTTTTAAAAAAAAAAAAAGG
CTGTAAAAAAAAAAAAAAAGGGG

Explanation: I set width to 24 which is number of desired character, if > is found and there is something stored in x do print that and set x value to empty string, if line with > is encountered do print it and go to next line. For every line do append current line content to x, if length of x is equal to or greater than width do print width first characters of x and remove these characters from x. After processing all lines do print x. Disclaimer solution: this solution assumes that ratio between current width and desired with is lesser than 0.5

(GNU Awk 5.0.1)

Assumptions:

  • all data lines are to be expanded to a max of 24 characters

One awk idea:

awk -v width=24 '                               # pass width in as awk variable "width"
function print_sequence() {
    if (sequence)                               # if sequence is not blank
       while (sequence) {                       # while sequence is not blank
             print substr(sequence,1,width)     # print 1st 24 characters
             sequence=substr(sequence,width+1)  # remove 1st 24 characters
       }
}

/^>/ { print_sequence()                         # flush previous set of data to stdout
       print                                    # print current input line
       next                                     # process next input line
     }
     { sequence=sequence $1 }                   # append data to our "sequence" variable

END  { print_sequence() }                       # flush last set of data to stdout
' fasta.in > fasta.out

This generates:

$ cat fasta.out
>seq1
AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAATGATGATGGAATGA
GGATTTAGGAGGGAGGAAAATTC
>seq2
CCCTCCGGGAAAAAAGAGGTTGCA
ATGCGCGTATTTATTTTTTTTTTT
TTTTTTTTTAAAAAAAAAAAAAGG
CTGTAAAAAAAAAAAAAAAGGGG

Yet another approach you could try, using awk's field and record separators:

awk -v width=24 '
  BEGIN {
    FS="\n"                            # Set the Field separator to newline
    RS=">"                             # Set the Record separator to ">"
    ORS=OFS=""                         # Set the Output Record and Field separator to an empty string
  }

  NR>1 {                               # Using ">" as a record separator the first record is empty, so skip
    header=$1                          # Using "\n" as the Field separator, $1 contains the header, save it in a variable
    $1=OFS                             # Assign an empty string to $1 so the record gets recalculated and the body becomes $0 i
                                       # with all newlines are removed, since OFS == ""
    gsub(".{" width "}", "&" FS)       # Append every "width" characters with a newline (FS)
    print RS header FS $0 FS           # Print a ">", the header, a newline, the body and a newline
  }
' fasta_in > fasta_out

Assuming the line that starts with > is never more than 24 chars long:

$ awk '{printf "%s", (/^>/ ? sep $0 ORS : $0); sep=ORS} END{print ""}' file | fold -w24
>seq1
AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAATGATGATGGAATGA
GGATTTAGGAGGGAGGAAAATTC
>seq2
CCCTCCGGGAAAAAAGAGGTTGCA
ATGCGCGTATTTATTTTTTTTTTT
TTTTTTTTTAAAAAAAAAAAAAGG
CTGTAAAAAAAAAAAAAAAGGGG
Related