Tengo un archivo delimitado con más de 2000 columnas. Me gustaría reorganizar las columnas (y todas las filas debajo de este encabezado) moviendo las que coinciden con un patrón determinado al final del archivo.

Mi entrada:

col1:aa01 col2:aa02 col3:nn08 col4:aa03 col5:nn08 col6:aa04
value1    value2    value3    value4    value5    value6

Desea que las columnas que terminan en 'nn08' se muevan hasta el final:

col1:aa01 col2:aa02 col4:aa03 col6:aa04 col3:nn08 col5:nn08
value1    value2    value4    value6    value3    value5 

Esto es lo que he reunido de los foros hasta ahora, pero obviamente no funciona:

awk 'BEGIN{FS=OFS="\t"} {a ~ /nn08/; for (i=2;i<NF; i++) $i=$(i+1); $NF=a; print}' in >out

Agradecería cualquier ayuda. Gracias.

1
berge2015 26 oct. 2017 a las 21:44

3 respuestas

La mejor respuesta

Utilizando awk one-liner

$awk 'FNR==1{ for(i=1; i<=NF; i++) if($i~/nn08/) a[i]++; } {for(i in a){str=str $i FS; $i=""} $0=$0 FS str; $1=$1; str=""}1' file

col1:aa01 col2:aa02  col4:aa03  col6:aa04 col3:nn08 col5:nn08

FNR==1{for(i=1; i<=NF; i++) if($i~/nn08/) a[i]++; }: Para la primera fila, es decir, el encabezado, recorra cada campo y if($i~/nn08/) es verdadero, luego establezca el valor de a[i]. a es una matriz asociativa donde i sería su clave y su valor se incrementaría (0 inicialmente si la clave no existe) Por ej. para la tercera columna a[3]=1 y similar a[5]=1 para la quinta columna. El objetivo es almacenar los números de columna como claves en a que se deben cambiar.

{for(i in a){str=str $i FS; $i=""} $0=$0 FS str; $1=$1; str=""}1 A continuación, en función de cada número de campo clave / columna i almacenado en a, agregue el valor de columna $i para finalizar la variable str y establezca column en {{X6 }} es decir, $i="". Después del bucle, agregue str al registro completo $0.

Nota: $1=$1 obliga a awk a reformar todo el registro que elimina los FS (espacios) adicionales creados mientras truncamos el campo a través de $i="".

0
Rahul Verma 26 oct. 2017 a las 19:41

Un trazador de líneas:

awk '{t = "";for(i=1; i<=NF; i++){if(FNR==1 && $i ~ /:nn08$/){h[i] = $i}if( i in h){t = ( t ? t OFS :"" ) $i;continue;}printf("%s%s",$i, OFS)}print t}' infile

Mejor legible:

awk '
    {
      t = "";
      for(i=1; i<=NF; i++)
      {

          # store column index in array h
          if(FNR==1 && $i ~ /:nn08$/){
                   h[i] = $i
          }

          # if column to be skipped then
          if( i in h)
          {
             # concatenate variable
             t = ( t ? t OFS :"" ) $i;

             # continue
             continue;      
          }

          # if ok, then print such column
          printf("%s%s",$i, OFS)
      }

      # print rest of them saved in variable
      print t
    }
    ' infile

Entrada:

$ cat infile
col1:aa01 col2:aa02 col3:nn08 col4:aa03 col5:nn08 col6:aa04
value1    value2    value3    value4    value5    value6

Salida:

$ awk '{t = "";for(i=1; i<=NF; i++){if(FNR==1 && $i ~ /:nn08$/){h[i] = $i}if( i in h){t = ( t ? t OFS :"" ) $i;continue;}printf("%s%s",$i, OFS)}print t}' infile
col1:aa01 col2:aa02 col4:aa03 col6:aa04 col3:nn08 col5:nn08
value1 value2 value4 value6 value3 value5
0
Akshay Hegde 26 oct. 2017 a las 19:30

Aquí hay otro

$ awk 'NR==1 {for(i=1;i<=NF;i++) if($i~/:nn08$/) p[i]} 
             {for(i=1;i<=NF;i++) if(!(i in p)) printf "%s",$i FS; 
              for(i in p) printf "%s",$i FS;
              print ""}' file

Se puede hacer más eficiente, pero tal vez lo suficientemente bueno como es.

0
karakfa 26 oct. 2017 a las 19:34