Encontrar palavras específicas e excluir todas as linhas depois

3

Eu tenho um arquivo contendo as seguintes informações:

    gene            3025..3855
                     /gene="Sp34_10000100"
                     /ID="Sp34_10000100"
     CDS             join(3025..3106,3722..3855)
                     /gene="Sp34_10000100"
                     /codon_start=1
                     /ID="Sp34_10000100.t1.cds1,Sp34_10000100.t1.cds2"
     mRNA            3025..3855
                     /ID="Sp34_10000100.t1"
                     /gene="Sp34_10000100"
     gene            12640..13470
                     /gene="Sp34_10000200"
                     /ID="Sp34_10000200"
     CDS             join(12640..12721,13337..13470)
                     /gene="Sp34_10000200"
                     /codon_start=1
                     /ID="Sp34_10000200.t1.cds1,Sp34_10000200.t1.cds2"
     mRNA            12640..13470
                     /ID="Sp34_10000200.t1"
                     /gene="Sp34_10000200"
     gene            15959..20678
                     /gene="Sp34_10000300"
                     /ID="Sp34_10000300"
     CDS             join(15959..16080,16268..16367,18913..19116,20469..20524,20582..20678)
                     /gene="Sp34_10000300"
                     /codon_start=1
                     /ID="Sp34_10000300.t1.cds1,Sp34_10000300.t1.cds2,Sp34_10000300.t1.cds3,Sp34_10000300.t1.cds4,Sp34_10000300.t1.cds5"
     mRNA            15959..20678
                     /ID="Sp34_10000300.t1"
                     /gene="Sp34_10000300"
     gene            22255..23085
                     /gene="Sp34_10000400"
                     /ID="Sp34_10000400"

Eu quero excluir todas as seções gene , mas as informações CDS e mRNA devem estar lá. A saída deve ser assim:

CDS             join(3025..3106,3722..3855)
                     /gene="Sp34_10000100"
                     /codon_start=1
                     /ID="Sp34_10000100.t1.cds1,Sp34_10000100.t1.cds2"
     mRNA            3025..3855
                     /ID="Sp34_10000100.t1"
                     /gene="Sp34_10000100"
     CDS             join(12640..12721,13337..13470)
                     /gene="Sp34_10000200"
                     /codon_start=1
                     /ID="Sp34_10000200.t1.cds1,Sp34_10000200.t1.cds2"
     mRNA            12640..13470
                     /ID="Sp34_10000200.t1"
                     /gene="Sp34_10000200"
     CDS             join(15959..16080,16268..16367,18913..19116,20469..20524,20582..20678)
                     /gene="Sp34_10000300"
                     /codon_start=1
                     /ID="Sp34_10000300.t1.cds1,Sp34_10000300.t1.cds2,Sp34_10000300.t1.cds3,Sp34_10000300.t1.cds4,Sp34_10000300.t1.cds5"
     mRNA            15959..20678
                     /ID="Sp34_10000300.t1"
                     /gene="Sp34_10000300"

Por favor, me dê qualquer sugestão de como fazer isso.

    
por Masum Billah 20.04.2017 / 10:30

3 respostas

4

o awk geralmente é mais fácil de ler e entender:

Aqui está um programa simples que escreve por padrão, e alterna um "wewrite" para "0" (= off, não vamos escrever) quando ele vê uma linha onde a primeira palavra é "gene", e coloca de volta quando ele vê uma linha onde a primeira palavra é "CDS" ou "mRNA":

awk '
  BEGIN                               { weprint=1 }

  ( $1 == "gene" )                    { weprint=0 }
  ( $1 == "CDS" ) || ( $1 == "mRNA" ) { weprint=1 }
  ( weprint == 1)                     { print $0 ;}

  '  file_to_read

BEGIN é feito antes de qualquer linha ser lida.

Os outros ( test ) { action if test successful } são analisados para cada linha de entrada (... a menos que uma ação contenha next , que então ignoraria o restante deles e, em vez disso, iria buscar a próxima linha de entrada)

Isso só imprimirá seções "CDS" e "mRNA" e não "gene"

Isso poderia ser "golfed" (por exemplo, a ação padrão para um 'teste' bem sucedido é imprimir $ 0, então você poderia ter apenas ( weprint == 1) como a última linha, mas seria menos claro de entender, imo ...)

    
por 20.04.2017 / 13:02
3
sed -e '
   /^ *gene /!b   # print non-gene block begin lines
   :a  
   $d; N          # do-while loop accumulates lines for gene block
   s/\n *\///;ta
   D              # clip the gene block
' yourfile

Você precisa entender que o modelo sed é ler um arquivo por linha  base, e sed comando na seção -e é aplicado em seqüência na  linha como é transformada a menos que haja instruções branching  envolvido. E uma sintaxe básica de sed é address command onde o comando pode  seja qualquer comando sed válido e address pode ser um destes: linenum ,   $ (= última linha), regex , range of addresses e, finalmente, nada significa que isso fica  aplicado a todas as linhas. Note que as linhas são armazenadas em um registro chamado pattern space .

Então, com esse material básico fora do caminho, vamos para o código sed -e real  à mão: b = > ramificar ao final do código sed e imprimir o espaço padrão. Isso significa que continuamos imprimindo qualquer linha que NÃO faça (a ! após o padrão de endereço) tenha a string gene como seu primeiro campo.

Quando finalmente atingimos o gene na primeira linha de campo, configuramos um loop do-while ( :a define uma marca a ser saltada para) para continuar acumulando as linhas no registro de espaço padrão ( N anexa a próxima linha; o comando s remove \n *\/ , que é a quebra de linha, seguida por espaços e / ) até o momento em que nenhuma das duas condições seja atendida, ou seja, atingimos a eof = > nós o deletamos ( $d = > deletamos o espaço padrão se estivermos na última linha) já que esse é um bloco de gene que apareceu em direção ao eof e deve ir.

OU atingimos o início do próximo bloco: se s conseguir encontrar e remover o padrão, o t pulará para :a , caso contrário (um novo bloco, então o padrão não foi encontrado), continuar. Agora, o espaço padrão contém todo o bloco do gene e a primeira linha do próximo bloco. Nós imediatamente deletamos o bloco do gene e com o início do próximo bloco nós vamos para o topo do código sed (é isso que o comando D faz).

    
por 20.04.2017 / 10:45
1

Eu não resisto a dar uma resposta perl quando temos sed e awk resposta!

# make perl complain when it should
use strict;
use warnings;

# declare variable
my $section;

# run through every line
while (<>) {
  # set the current section to 'gene', 'CDS' or 'mRNA' when it matches
  $section = $1 if /^\h*(gene|CDS|mRNA)/;

  # print if the current section is not 'gene'
  print if $section ne 'gene';
}
    
por 20.04.2017 / 15:00

Tags