Técnica para concatenar grupos de linhas consecutivas, delimitadas por padrão

2

Eu tenho uma lista como esta:

$$<002L_tbfl
Putative transcription factor 001R;
GO:0006355
GO:0046782
GO:0006351
IPR007031
$$<002L_FRG3G
Uncharacterized protein 002L;
GO:0033644
GO:0016021
IPR004251

Eu quero que cada $$< inicie uma nova linha, com as seguintes entradas na mesma linha (separadas por tabulação), até que $$< apareça novamente. Assim:

$$<002L_tbfl    Putative transcription factor 001R; GO:0006355  GO:0046782  GO:0006351  IPR007031
$$<002L_FRG3G   Uncharacterized protein 002L;   GO:0033644  GO:0016021  IPR004251

Meu método até agora tem sido:

tr '\n' '\t'   < stage1 > stage2
sed 's/$$</\n/g' stage2 > stage3

A coisa é que o acima funciona totalmente bem em arquivos pequenos, mas no meu arquivo de 4GB parece funcionar, em seguida, retorna um arquivo em branco dentro de uma fração do tempo sem erros ou mensagens. Eu também tentei tr '$$<' '\n' e isso não acontece; produz um arquivo estranho.

    
por biogeek89 11.09.2016 / 04:55

5 respostas

1

Veja como fazer isso em sed :

sed -n '/$$</! H; /$$</{x; s/\n/\t/gp}; ${x; s/\n/\t/gp}' stage1 > stage3

Em pedaços:

  • sed -n significa não imprimir saída padrão (ou seja, a entrada massageada); imprima somente quando houver um comando p .
  • /$$</! H significa que você vê uma linha não contendo $$< , anexá-lo ao espaço " h antigo" (ou seja, uma área de preparação). O ! inverte a lógica normal, significa "faça isso para linhas que não satisfazem essa condição". Se você precisar ignorar $$< que ocorre no meio de uma linha, altere este (e o próximo comando) para usar /^$$</ . (Se você precisar processar $$< no meio de uma linha de maneira diferente - por exemplo, insira uma nova linha antes dela - edite sua pergunta para dizer isso.)

    Se você acrescentar uma linha ao espaço de espera quando já houver algo lá (no espaço de espera), sed insere uma nova linha entre eles, então isso vai construir texto no espaço de espera que se parece com isso:

    $$<002L_tbflnewlinePutative transcription factor 001R;newlineGO:0006355…

    O espaço de espera, como o "espaço de padrão" (o buffer de linha de trabalho comum) geralmente não terá uma nova linha explícita no final (é implícita). Claro que é possível inserir explicitamente novas linhas nos espaços.

  • /$$</{…} significa que os comandos dentro das chaves nas linhas que contêm $$< .

    • x significa e x altera o conteúdo do espaço de espera e do espaço padrão.
    • s/\n/\t/gp significa - bem, é óbvio, não é? - isso significa substituir a nova linha pela guia (no espaço padrão) g lobally e p rint o resultado.

    Quando este comando lê a primeira linha da sua entrada (que contém $$< ), o x move essa linha ( $$<002L_tbfl ) a partir do espaço padrão para o espaço de espera e move o conteúdo anterior do espaço de armazenamento para o espaço de padrão. Mas, desde que o conteúdo inicial do espaço de espera é nada, isso significa que não há nada para o comando s trabalhar. Posteriormente, quando você vir $$< (por exemplo, na linha 7), ele traz o texto com as novas linhas incorporadas (conforme ilustrado acima) no espaço padrão e (como descrito) substitui todas as novas linhas por tabulações e imprime o resultado.

  • ${…} significa fazer os comandos dentro das chaves quando você chegar ao final da entrada. Estes são os mesmos comandos que fazemos quando vemos um $$< , para lavar a última linha (ou seja, o último grupo de linhas) do espaço de espera.

Aviso: não é garantido que isso funcione no POSIX sed . Eu testei no GNU sed .

    
por 11.09.2016 / 07:29
1
$ cat ip.txt 
$$<002L_tbfl
Putative transcription factor 001R;
GO:0006355
GO:0046782
GO:0006351
IPR007031
$$<002L_FRG3G
Uncharacterized protein 002L;
GO:0033644
GO:0016021
IPR004251

$ perl -ne 'chomp if !eof; if($. > 1){print /\$\$</ ? "\n" : "\t"} print' ip.txt 
$$<002L_tbfl    Putative transcription factor 001R; GO:0006355  GO:0046782  GO:0006351  IPR007031
$$<002L_FRG3G   Uncharacterized protein 002L;   GO:0033644  GO:0016021  IPR004251
  • chomp if !eof remove nova linha de todas as linhas de entrada, exceto a última linha do arquivo
  • if($. > 1) número da linha de entrada maior que 1
  • print /\$\$</ ? "\n" : "\t" adicionar nova linha se a linha corresponder a $$< else adicionar separador
  • print imprime a linha de entrada
por 12.09.2016 / 07:56
0

Presumivelmente, há uma limitação de 32 bits em vigor, portanto somente o processamento de fluxo é possível. Você pode usar awk , como em

awk 'NR==1 {printf "%s",$0; next;} $1~/^\$\$</ {printf "\n%s",$0; next;} {printf "\t%s",$0;}' < file

Isso imprimirá todas as linhas de entrada em sucessão sem novas linhas, exceto que as linhas (após a primeira) começando com $$< ganham novas linhas iniciais.

Possivelmente você deseja uma nova linha final, que seria necessária e a estrofe END. Veja man awk para essas variações.

    
por 11.09.2016 / 05:35
0

Você pode simplesmente salvar a primeira linha que corresponde ao buffer de retenção e excluí-la; acumule linhas que não coincidam no espaço de espera e exclua-as, se não a última linha, em seguida, nos buffers de troca de linhas restantes e traduza todas as novas linhas para espaços:

sed '1{h;d;};/$$</!{H;$!d;};x;y/\n/ /' file

Observe que o espaço usado no comando y é uma guia literal.

    
por 11.09.2016 / 14:25
0

Funciona com Mawk e Gawk 3.x no Ubuntu 12, que suportam RS sendo um regex.

$ awk 'BEGIN { RS="\$\$<"; FS="\n"; OFS="\t" } NF && $1="$$<"$1' data

Saída:

$$<002L_tbfl    Putative transcription factor 001R; GO:0006355  GO:0046782  GO:0006351  IPR007031   
$$<002L_FRG3G   Uncharacterized protein 002L;   GO:0033644  GO:0016021  IPR004251

Nós simplesmente usamos $$< como separador de registro e nova linha como o separador de campo.

Isso significa que:

  • recebemos um registro vazio, pois a entrada começa com nosso separador de registros. Eliminamos isso usando NF como condição: o número de campos deve ser diferente de zero.
  • $$< é removido da entrada. Colocamos de volta em $1 .

Para imprimir os campos com tabulações intermediárias, configuramos a guia como o separador do campo de saída ( OFS ). { print } é a ação padrão para um padrão, por isso omitimos isso.

O fato de modificarmos $1 também tem o efeito colateral de atualizar a variável de registro $0 unindo todos os campos com OFS . Sem essa atualização, os registros originais seriam impressos textualmente, novas linhas e todos.

    
por 11.09.2016 / 15:32