Imprime texto antes e depois da correspondência, de um início específico e até uma sequência final

2

Estou tentando extrair entradas de um grande arquivo Genbank, com milhares de entradas. Para uma string de pesquisa, estou usando um nome de gene único - que funciona bem. O problema é que eu gostaria de imprimir a entrada inteira para esse gene em particular - as entradas começam com a palavra LOCUS e terminam com //, e contêm o nome do gene em algum ponto entre elas. Compreendo que posso usar as bandeiras% greper%, -A e -B do grep para imprimir as linhas n após / antes de uma correspondência de cadeia, mas as entradas reais são variáveis em tamanho. Como eu usaria o grep para procurar pela minha string (nome do gene), e depois imprimir todas as linhas antes da partida até e incluindo uma linha começando com "LOCUS", e todas as linhas até e incluindo uma linha indicando o fim do entrada, que é apenas "//"?

Estou aberto a todas as sugestões. Existe uma maneira de fazer com que os sinalizadores -C e -A correspondam a sequências de caracteres ("LOCUS" e "//") ou algo nesse sentido? Eu deveria estar usando o awk?

Edit: Este é um exemplo simplificado de entrada - cada registro começa com "LOCUS" e termina com "//". Este exemplo contém três registros:

LOCUS scaffold1|size100
/gene="gene1"
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
//
LOCUS scaffold99|size
/gene="gene2"
CGTTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
//
LOCUS scaffold199|size1000
/gene="gene3"
AGTTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
AGTTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
AGTTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
//

Eu gostaria de procurar por "gene2" e imprimir o texto da primeira instância de "LOCUS" antes da partida até a primeira em "//" após a partida. Idealmente, gostaria da seguinte saída:

LOCUS scaffold99|size
/gene="gene2"
CGTTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
GATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACAGATTACA
//
    
por anth 29.04.2018 / 22:12

3 respostas

2

Isso é bastante fácil em awk :

awk -vtarget=fox '
    /LOCUS/ { in_gene = 1 }
    in_gene { if (gene == "") gene = $0; else gene = gene ORS $0; }
    $0 ~ target { found = 1 }
    /\/\//  { if (in_gene && found) print gene
              gene = ""; in_gene = 0; found = 0
            }
    '
  • Defina a variável target para a string (nome do gene) que você está procurando. Eu usei fox como exemplo.
  • Quando vemos a palavra LOCUS , sabemos que estamos vendo um gene.
  • Enquanto estivermos olhando para um gene, acumulemos seu conteúdo. A primeira linha (a linha LOCUS ) é atribuída apenas à variável gene . Posteriormente, adicionamos (anexamos) a linha atual ( $0 ) à variável gene com uma nova linha (ORS = Output Record Separator) entre o valor antigo e o valor adicionado.
  • Se o gene atual contiver o nome do gene que você está procurando, defina o sinalizador found .
  • Temos que usar o feio /\/\// para procurar por // . Quando vemos uma, verificamos se o gene atual é o que procuramos, e, em caso afirmativo, imprima-o. Em seguida, redefina para continuar pesquisando. Se você tem certeza de que o gene que você está procurando ocorre apenas uma vez no arquivo (ou se você quiser apenas a primeira ocorrência), você poderia simplesmente sair daqui.
por 29.04.2018 / 22:48
2

Quando cada registro Gene está especificando que é entre LOCUS...// , você pode fazer:

gawk '/gene2/{printf $0 RS}' RS='\n//\n' infile

Definimos a RS com um valor único para o qual cada registro termina, digamos " \n ewline //\n ewline" (uma linha contendo apenas // ), depois para cada registro correspondido /gene2/ imprime o registro $0 e reverta RS .

Nota: Para gerenciar o RS quando se estava incluindo espaço em branco inicial / final (Espaços / Tabs), você pode alterar para RS='\n( |\t)*//( |\t)*\n' , mas é necessário usar RT ? ( GNU extensão awk) para manter o RS intacto ou imprime diretamente "//" .

gawk '/gene2/{printf $0 RT}' RS='\n( |\t)*//( |\t)*\n' infile

de man gawk :

RS The input record separator, by default a newline.

RT The record terminator. Gawk sets RT to the input text that matched the character or regular expression specified by RS.

?: After the end of the record has been determined, gawk sets the variable RT to the text in the input that matched RS. When RS is a single character, RT contains the same single character. However, when RS is a regular expression, RT contains the actual input text that matched the regular expression.

    
por 30.04.2018 / 08:04
1
sed -ne '
   /^LOCUS/,\|^//|!d
   H;/^LOCUS/h
   \|^/gene="gene2"|{
      s/.*//;x;H
   }
   \|^//|!d;g
   s/^\n//p
'       input_file

Trabalhando:

¶ O operador de faixa "," pode ser usado aqui

¶ Primeiro selecione o intervalo correto que é o locus começa e // termina o intervalo.

¶ Armazene as linhas no espaço de espera.

¶ Quando encontramos essa linha dourada com o gene2, colocamos um caractere de nova linha no início como uma bandeira para nos lembrar quando chegar a hora de imprimir ou não imprimir.

¶ // line ativará a atividade de impressão com base no fato de termos visto a nova linha na frente na área de espera.

    
por 29.04.2018 / 23:47