¿Cómo usar sort en un comando awk print?

8

Tengo un par de comandos en un script awk que estoy escribiendo:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2}

Qué salidas:

Here are some players and their numbers, sorted by last name
Lebron James 23
Kevin Durant 35
Kobe Bryant 24
Blake Griffin 32
Dikembe Mutumbo 55

¿Cómo puedo usar el sortcomando en mi script awk para ordenar SOLAMENTE a los jugadores y sus números?

KM142646
fuente
3
Dados sus comentarios sobre las respuestas, parece que está confundiendo el script awk y el shell en su pregunta. Parece que desea ordenar dentro de su script awk , no en el script de shell que lo invoca. Si eso es correcto, edite su pregunta y reemplace las dos ocurrencias de 'shell' por 'awk'. En una nota separada: sí, awk tiene una función de clasificación, pero es bastante complicada: debe almacenar todas las líneas en una matriz, tecleadas en su segundo campo, del que deberá extraerlas xy luego establecerlas PROCINFO["sorted_in"]en un valor críptico, luego genera la matriz. Yo no iría allí
zwets
1
Quiero decir: no iría allí dada la simplicidad de ... | sort -k2,2.
zwets
@zwets ¿Cómo implementaría ...| sort -k2,2si hay otras líneas que necesitan imprimirse? Verifica la pregunta editada.
KM142646
Al echounir la línea de encabezado desde el shell, luego ejecute la awk | sorttubería.
zwets

Respuestas:

12

puedes agregar | sort -k2a tu comando. Esto se ordenará alfabéticamente según la segunda columna.

Ejemplo:

$ echo "Lebron James 23
Kevin Durant 35
Kobe Bryant 24
Blake Griffin 32
Dikembe Mutumbo 55" | sort -k2

resultados en

Kobe Bryant 24
Kevin Durant 35
Blake Griffin 32
Lebron James 23
Dikembe Mutumbo 55
Wayne_Yux
fuente
Lamentablemente, estoy usando un script y el comando de clasificación se combinará con muchas otras salidas. ¿Hay alguna manera de ordenar la salida {print x, $2}directamente en el código del script? Recibo un error al realizar la tubería if(sum[x] > 500) {print x, $2} | sort -k2.
KM142646
3
@KMoy: if(sum[x] > 500) {print x, $2}es el código Awk mientras que | sort -k2es un comando de shell. Obviamente no puedes mezclar los dos así porque son idiomas diferentes. En su lugar, debe aplicar el sortcomando a la salida del intérprete Awk que ejecuta su fragmento de código Awk. Si no sabe a qué me refiero, expanda su pregunta para darnos una imagen completa.
David Foerster el
1
Estás escribiendo un script de shell, ¿verdad? Entonces tienes dos opciones: 1. ejecutar ./my-script.sh | sort -k2. 2. agregar `| ordena -k2` a la línea de tu script que produce la salida dada en tu pregunta.
Wayne_Yux
@Wayne_Yux Revise las ediciones realizadas a la pregunta original.
KM142646
Entonces probablemente necesites la respuesta de @steeldriver
Wayne_Yux
9

Aunque no lo recomendaría (dada la relativa simplicidad de canalizar el resultado a través de un sortcomando externo ), puede hacerlo al menos con versiones recientes de GNU awk (al menos 4.0 IIRC), como se describe en Clasificación de valores e índices de matriz con gawk

A continuación, le mostramos cómo podría implementarlo, suponiendo que tenga los datos en una matriz asociativa en la que se encuentra el índice Firstname Lastname. Primero, debe definir una función de comparación personalizada que divida el índice, primero compare Lastnameluego (como un desempate) en, Firstnamep. Ej.

function mycmp(ia, va, ib, vb, sa, sb) {
  if(split(toupper(ia), sa) && split(toupper(ib), sb)) {
    if(sa[2] < sb[2]) return -1;
    else if (sa[2] > sb[2]) return 1;
    else {
      # compare first names
      if(sa[1] < sb[1]) return -1;
      else if (sa[1] > sb[1]) return 1;
      else return 0;
    }
  }
  else return 0;
}

Ahora puede usar el PROCINFO["sorted_in"]método de clasificación de matriz mencionado en los comentarios de @zwets

PROCINFO["sorted_in"] = "mycmp";
for(i in a) print i, a[i];

Poniendo todo junto

#!/usr/bin/gawk -f

function mycmp(ia, va, ib, vb, sa, sb) {
  if(split(toupper(ia), sa) && split(toupper(ib), sb)) {
    if(sa[2] < sb[2]) return -1;
    else if (sa[2] > sb[2]) return 1;
    else {
      # compare first names
      if(sa[1] < sb[1]) return -1;
      else if (sa[1] > sb[1]) return 1;
      else return 0;
    }
  }
  else return 0;
}

{
  a[$1" "$2] = $3;
}

END {
  PROCINFO["sorted_in"] = "mycmp";
  for(i in a) print i, a[i];
}

Pruebas:

$ ./namesort.awk yourfile
Kobe Bryant 24
Kevin Durant 35
Blake Griffin 32
Lebron James 23
Dikembe Mutumbo 55

En versiones menores o anteriores de awk, su mejor opción puede ser almacenar los datos indexados Lastname Firstname, ordenarlos con los convencionales asorti, luego dividir e intercambiar los campos de los índices a medida que recorre la matriz para imprimirla:

awk '
  {a[$2" "$1]=$3} 
  END {
    n=asorti(a,b); for (i=1;i<=n;i++) {split(b[i],s); print s[2], s[1], a[b[i]]}
}' yourfile
conductor de acero
fuente
5

Para sortsolo el segundo campo separado por espacios en blanco, use la tecla -k2,2:

... | sort -k2,2

por defecto sort realiza la clasificación lexicográficamente.

Tenga en cuenta que, si no menciona el último campo para la clave de clasificación, es decir, si solo lo usa -k2, es posible que no obtenga el resultado deseado, ya que esto se hará de sortacuerdo con todos los campos comienzan desde el segundo.

También consultar man sort.

heemayl
fuente
Por favor revise el comentario en la publicación de Wayne para lo que necesito
KM142646
1

Tratar

awk -f myscript.awk | sort -k2

Donde myscript.awk contiene comandos puramente awk.

Si su script real es un script de shell, tiene varias opciones que incluyen

  • Salida de tubería a través del ordenamiento. ./myscript.bash | sort -k2
  • Reescribe el código como una función dentro del script en
    lugar de

    $ cat t1
    #!/bin/bash
    for i in 2 4 3 1 5;
    do
      echo $i
    done
    
    $ ./t1
    2
    4
    3
    1
    5
    

    Hacer

    $ cat t2
    #!/bin/bash
    function foo {
      for i in 2 4 3 1 5;
      do
        echo $i
      done
    }
    foo | sort
    
    $ ./t2
    1
    2
    3
    4
    5
    

Pero tenga en cuenta que también puede aplicar el ordenamiento a la estructura do ... done en lugar de hacer una función.

    do
       echo $i
    done | sort
RedGrittyBrick
fuente
¿Por qué definir la función?
zwets
@zwets, hace que sea más fácil alimentar los resultados del código arbitrario, incluidas las estructuras de control en bucle, a través de una tubería. Hay casos en los que es innecesario, pero me parece un patrón general útil. Editaré mi respuesta para demostrar esto.
RedGrittyBrick
1

Para ordenar sus datos para imprimir:

  • Suponga que desea imprimir el segundo campo (espacios en blanco separados) use esto:

    awk '{print $2}' data.txt | sort
    

    p.ej:

    $cat>data.txt
    1 Kedar 20
    2 Amit 30
    3 Rahul 21
    ^C
    
    $awk '{print $2}' | sort
    Amit
    Kedar
    Rahul
    
  • Si desea imprimir la totalidad de su data.txtpero ordenado en la columna 2, entonces:

    $awk '{print}'|sort -k2
    2 Amit 30
    1 Kedar 20
    3 Rahul 21
    

Use esta (s) lógica (s) en su requerimiento.

Puede usar man sortpara características más interesantes de sort.

Abdul Sattar Mapara
fuente
0

¿Qué pasa a continuación:

 awk 'BEGIN{str="1\n2\n3\n4"; system("echo -e \""str"\" | sort -r")}'

Funciona cuando lo probé.

Fei Wang
fuente
0
print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2"}

Para ordenar la salida a un archivo:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2 > sortedFile"}
DMBailey
fuente