Cómo extraer múltiples bits de información que aparecen en diferentes líneas dentro del mismo archivo de texto

Cómo extraer múltiples bits de información que aparecen en diferentes líneas dentro del mismo archivo de texto

Estoy intentando extraer el ID de secuencia y el número de grupo que aparecen en diferentes líneas dentro del mismo archivo de texto.

La entrada parece

>Cluster 72
0   319aa, >O311_01007... *
>Cluster 73
0   318aa, >1494_00753... *
1   318aa, >1621_00002... at 99.69%
2   318aa, >1622_00575... at 99.37%
3   318aa, >1633_00422... at 99.37%
4   318aa, >O136_00307... at 99.69%
>Cluster 74
0   318aa, >O139_01028... *
1   318aa, >O142_00961... at 99.69%
>Cluster 75
0   318aa, >O300_00856... *

El resultado deseado es el ID de secuencia en una columna y el número de grupo correspondiente en la segunda.

>O311_01007  72
>1494_00753  73
>1621_00002  73
>1622_00575  73
>1633_00422  73
>O136_00307  73
>O139_01028  74
>O142_00961  74
>O300_00856  75

¿Alguien puede ayudarme con esto?

Respuesta1

Con awk:

awk -F '[. ]*' 'NF == 2 {id = $2; next} {print $3, id}' input-file
  • dividimos campos en espacios o puntos con-F '[. ]*'
  • con líneas de dos campos, (las >Clusterlíneas), guarde el segundo campo como ID y pase a la siguiente línea
  • con otras líneas, imprima el tercer campo y el ID guardado

Respuesta2

Puedes usar awkpara esto:

awk '/>Cluster/{
      c=$2;
      next
    }{
      print substr($3,2,length($3)-4), c
    }' file

La primera declaración de bloque captura la ID del clúster. La segunda declaración de bloque (la predeterminada) extrae los datos deseados e imprimelos.

Respuesta3

Aquí hay una alternativa con Ruby como frase ingeniosa:

ruby -ne 'case $_; when /^>Cluster (\d+)/;id = $1;when /, (>\w{4}_\w{5})\.\.\./;puts "#{$1} #{id}";end' input_file

o difundir en varias líneas:

ruby -ne 'case $_
when /^>Cluster (\d+)/
  id = $1
when /, (>\w{4}_\w{5})\.\.\./
  puts "#{$1} #{id}"
end' input_file

Supongo que sólo es más legible que la awkversión si conoces Ruby y regexen. Como beneficio adicional, este código podría ser un poco más sólido que simplemente dividir las líneas, porque busca el texto circundante.

Respuesta4

Perla:

$ perl -ne 'if(/^>.*?(\d+)/){$n=$1;}else{ s/.*(>[^.]+).*/$1 $n/; print}' file 
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75

Explicación

  • perl -ne: lea el archivo de entrada línea por línea ( -n) y aplique el script proporcionado por -ea cada línea.
  • if(/^>.*?(\d+)/){$n=$1;}: si esta línea comienza con >, busque el tramo más largo de números al final de la línea y guárdelo como $n.
  • else{ s/.*(>[^.]+).*/$1 $n/; print: si la línea no comienza con >, reemplace todo con el tramo más largo de .caracteres que no sean caracteres después de >( >[^.]+), es decir, el nombre de la secuencia ( $1porque tenemoscapturadola coincidencia de expresiones regulares) y el valor actual de $n.

O, para un enfoque más extraño:

$ perl -lane 'if($#F==1){$n=$F[1]}else{$F[2]=~s/\.+$//; print "$F[2] $n"}' file 
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75

Esta es sólo una forma un poco más engorrosa de hacer la misma idea básica que los distintos awkenfoques. Lo incluyo para completarlo y para los fanáticos de Perl. Si necesita una explicación, simplemente use las soluciones awk :).

información relacionada