awk: extrae columnas delimitadas por tabulaciones que coinciden con subcadenas en la primera línea

awk: extrae columnas delimitadas por tabulaciones que coinciden con subcadenas en la primera línea

Me gustaría extraer columnas delimitadas por tabulaciones de un archivo de texto ("columns.txt") en el que el encabezado (primera línea) coincide con ciertas cadenas enumeradas en otro archivo de texto ("strings.txt").

"columnas.txt" tiene este aspecto:

rs2438689   rs54666437   rs9877702046   rs025436779...
0           0            0              1
1           1            2              2 
0           1            2              0 
...         ...          ...            ...

"strings.txt" se ve así:

rs2438689
rs9877702046   
...

El archivo de texto de salida "output.txt" debería verse así (delimitado por tabulaciones):

rs2438689   rs9877702046...
0           0              
1           2               
0           2               
...         ...    

¿Alguna sugerencia sobre cómo hacer esto con awk? ¡Gracias!

Respuesta1

En lugar de Awk, ¿qué tal si hacemos una lista de nombres de columnas separados por comas strings.txty la usamos como una lista de namedcols para csvtool:

$ csvtool -t TAB -u TAB namedcol "$(paste -sd, < strings.txt)" columns.txt
rs2438689   rs9877702046
0   0
1   2
0   2
... ...

o de manera similar con csvcut/csvformatel basado en Python csvkit:

$ csvcut -tc "$(paste -sd, < strings.txt)" columns.txt | csvformat -T
rs2438689   rs9877702046
0   0
1   2
0   2
... ...

Respuesta2

Conperl

$ perl -F'\t' -lane 'if(!$#ARGV){ $h{$_}=1 }
                     else{ @i = grep { $h{$F[$_]} == 1 } 0..$#F if !$c++;
                           print join "\t", @F[@i]}' strings.txt columns.txt
rs2438689   rs9877702046
0   0
1   2
0   2
  • if(!$#ARGV){ $h{$_}=1 }para el primer archivo de entrada, cree un hash con el contenido de la línea como clave
  • @i = grep { $h{$F[$_]} == 1 } 0..$#F if !$c++para la primera línea del segundo archivo, cree una lista de índice de todos los nombres de columnas coincidentes del hash
  • print join "\t", @F[@i]imprimir las columnas coincidentes

Respuesta3

Modificandomi solución a tu pregunta anterior:

awk -F '\t' -f script.awk strings.txt columns.txt

dónde script.awkes

BEGIN { OFS = FS }

FNR == NR {
    columns[$1] = 1
    next
}

FNR == 1 {
    for (i = 1; i <= NF; ++i)
        if ($i in columns)
            keep[i] = 1
}

{
    nf = split($0, fields, FS)
    $0 = ""
    j = 0

    for (i = 1; i <= nf; ++i)
        if (i in keep)
            $(++j) = fields[i]

    print
}

Aquí, el FNR == NRbloque solo se ejecutaría mientras se lee el primer archivo enumerado en la línea de comando ( strings.txt). Completaría la columnsmatriz con claves que son los nombres de las columnas. El resto del código esmás o menossin cambios con respecto a la solución anterior, aparte de donde verificamos si la columna actual es una que nos gustaría mantener (en el FNR == 1bloque).


Abordar elpreguntas en comentarios:

Para copiar siempre las primeras seis columnas y cortar los encabezados de las columnas en _, cambie

FNR == 1 {
    for (i = 1; i <= NF; ++i)
        if ($i in columns)
            keep[i] = 1
}

en

FNR == 1 {
    for (i = 1; i <= NF; ++i) {
        sub("_.*", "", $i)
        if (i <= 6 || $i in columns)
            keep[i] = 1
    }
}

Respuesta4

Hecho usando el siguiente script, puede que tarde mucho en funcionar bien.

k=wc -l file1| awk '{print $1}'

for ((i=1;i<=$k;i++));  do for j in `cat file2`; do awk -v i="$i" -v j="$j" '$i == j {x=NR+k}(NR<=x){print $i}' file1; done ; done>final.txt

z=`wc -l final.txt| awk '{print $1}'`

for ((i=1;i<=$z;i++)); do j=$(($i+3)); sed -n ''$i','$j'p' final.txt >file_starting_with_$i.txt; i=$j; done

paste file_starting_with*

producción

rs2438689   rs9877702046
0       0
1       2
0       2

información relacionada