Tengo un archivo fruit
que tiene el siguiente contenido:
Apples, 12 Pears, 50 Cheries, 7 Strawberries, 36 Oranges, 2
Me gustaría ordenar los datos numéricos del archivo:
for(i=1;i<=NF;i++)j+=$i;printf "Fruit %d%s, %d\n",NR,OFS,$1,j | sort -k 2 > "numbers"; j=0"
Para ejecutar el script awk, ejecuto el comando :
awk -f numbers fruit
El archivo de números tiene el mismo contenido que la fruta, pero su primer y segundo campo se copian en el archivo de números.
Comentarios
Responder
GNU awk le ofrece una forma ordenada de controlar cómo atraviesa una matriz: consulte Control de recorrido de matriz y Control de escaneo
gawk -F", " " {fruit[$1] = $2} END { OFS = FS printf "\nordered by fruit name\n" PROCINFO["sorted_in"] = "@ind_str_asc" for (f in fruit) print f, fruit[f] printf "\nordered by number\n" PROCINFO["sorted_in"] = "@val_num_desc" for (f in fruit) print f, fruit[f] } " fruit
salidas
ordered by fruit name Apples, 12 Cheries, 7 Oranges, 2 Pears, 50 Strawberries, 36 ordered by number Pears, 50 Strawberries, 36 Apples, 12 Cheries, 7 Oranges, 2
Respuesta
De hecho, puede pasar awk «s print
a "sort"
(observe las comillas):
$ awk "{print "Fruit",NR, $0 | "sort -k 2 -t, -rn"}" fruit Fruit 2 Pears, 50 Fruit 4 Strawberries, 36 Fruit 1 Apples, 12 Fruit 3 Cheries, 7 Fruit 5 Oranges, 2
Entonces, para escribir en numbers
, puede hacer:
awk "{print "Fruit",NR, $0 | "sort -k 2 -t, -rn > numbers"}" fruit
Tenga en cuenta que simplifiqué un poco su awk. No es necesario utilizar printf
aquí o imprimir explícitamente OFS
ya que no lo vas a cambiar en ninguna parte. I al así que no vea lo que está haciendo su for(i=1;i<=NF;i++)j+=$i
. Ya tienes el número con NR
y tu printf
no estaba «t usando j
de todos modos.
Comentarios
- En lugar de llamar a sort inside awk, ‘ es más simple y más eficiente para simplemente imprimir en awk y canalice la salida de awk para ordenar:
awk '{print ...}' fruit | sort ...
. - @EdMorton ¡oh, absolutamente! Yo nunca usaría este enfoque, ¿qué ‘ ¿es el punto? Pero esto es lo que pidió el OP .
- A menudo encuentro un requisito para ordenar dentro de gawk, cuando no ‘ no quiero ordenar toda la salida. Por ejemplo, recopilar e informar estadísticas por separado para cada archivo de entrada. Puedo usar un método de decorar / ordenar / recortar para personalice claves simples a partir de datos complejos (por ejemplo, clasifique las sobrecargas de equipos eléctricos utilizando una matriz lateral de clasificaciones máximas). Además, la clasificación externa utiliza archivos de trabajo de disco y una estrategia de división / fusión. sort puede usar mejores métodos.
- @JoeSkora, no ‘ no es necesario generar una subcapa de awk y luego esperar que el almacenamiento en búfer de todos los interesados lleve a la salida desde el subshell llegando a stdout después del resto de la salida del comando awk en lugar de antes o, si corresponde, en el medio. Solo haz
awk '{print (NR>1), $0}' | sort -k1,1n -k2 | cut -d' ' -f2-
- @EdMorton Me gusta imprimir el condicional, gran idea. La última parte se puede simplificar aún más dejando esto.
awk '{print (NR>1),$0}' | sort ... | cut -c3-
.
Responder
Debo haber tenido un problema con SunOS nawk en 2002. Encontré mi script de prueba que contenía tres implementaciones de awk que se ejecutan dentro de awk que no son de GNU:
(a) eSort: usa un archivo de trabajo y vuelve a leer a través de una tubería que ejecuta el comando sort. No es bueno en mi caso, porque estaba haciendo cosas a través de ssh para el monitoreo sin agentes, y los archivos de trabajo externos eran demasiado invasivos para nuestros servidores en vivo.
(b) qSort: una clasificación de partición recursiva. Rendimiento malo para datos grandes y rompe la pila en mawk para> 2000 elementos. Aunque divertido de escribir.
(c) hSort: un algoritmo de clasificación in situ en 15 líneas. Este montón usa un algoritmo de indexación para soportar un árbol binario (ver Wikipedia).
Este script bash contiene funciones awk hSort y hUp que implementan la ordenación real. Una línea de acción pone toda la entrada en una matriz y el bloque END llama a hSort e informa los resultados.
Los datos de entrada son el contenido de «man bash», una vez como líneas y otra vez como palabras. Usamos wc para demostrar que no se perdió nada, y ordenamos -c para probar que la salida está ordenada. Los tiempos incluyen la sobrecarga de lectura e impresión.
Esta es la toma de prueba:
Paul--) ./hSort Sorted 5251 elements. real 0m0.120s user 0m0.116s sys 0m0.004s 5251 44463 273728 hSort.raw sort: hSort.raw:2: disorder: 5251 44463 273728 hSort.srt Sorted 44463 elements. real 0m1.336s user 0m1.316s sys 0m0.008s 44463 44463 265333 hSort.raw sort: hSort.raw:3: disorder: Commands 44463 44463 265333 hSort.srt
Esta es la secuencia de comandos. ¡Disfruta!
#! /bin/bash export LC_ALL="C" #### Heapsort algorithm. function hSort { #:: (void) < text local AWK=""" #.. Construct the heap, then unfold it. function hSort (A, Local, n, j, e) { for (j in A) ++n; for (j = int (n / 2); j > 0; --j) hUp( j, A[j], n, A); for (j = n; j > 1; --j) { e = A[j]; A[j] = A[1]; hUp( 1, e, j - 1, A); } return (0 + n); } #.. Given an empty slot and its contents, pull any bigger elements up the tree. function hUp (j, e, n, V, Local, k) { while ((k = j + j) <= n) { if (k + 1 <= n && STX V[k] < STX V[k + 1]) ++k; if (STX e >= STX V[k]) break; V[j] = V[k]; j = k; } V[j] = e; } { U[++nU] = $0; } END { sz = hSort( U); printf ("\nSorted %s elements.\n", sz) | "cat 1>&2"; for (k = 1; k in U; ++k) print U[k]; } """ mawk -f <( printf "%s\n" "${AWK}" ) } #### Test Package Starts Here. function Test { time hSort < hSort.raw > hSort.srt for fn in hSort.{raw,srt}; do wc "${fn}"; LC_ALL="C" sort -c "${fn}"; done } AWK_LINE="{ sub (/^[ \011]+/, ""); print; }" AWK_WORD="{ for (f = 1; f <= NF; ++f) print $(f); }" #xxx : > hSort.raw; Test #.. Edge cases. #xxx echo "Hello" > hSort.raw; Test #xxx { echo "World"; echo "Hello"; } > hSort.raw; Test man bash | col -b | mawk "${AWK_LINE}" > hSort.raw; Test man bash | col -b | mawk "${AWK_WORD}" > hSort.raw; Test
Responder
HeapSort se puede escribir en awk estándar en menos de 20 líneas. No es increíblemente rápido, pero se adapta al lenguaje razonablemente bien.
Comentarios
- Oh, no ‘ t publicarlo. Afirmé su existencia y lo dejé como un ejercicio para el lector.
- Publiqué el código y la prueba el 9 de enero de 2020
asort
. Podría haber jurado que no ‘ t, por alguna razón. ¡Gracias! No estoy seguro de si valdría la pena, ya que ‘ tendrías que leer todo el archivo en una matriz y luego ordenar la matriz, por lo que ordenar la salida probablemente sea más eficiente. pero ‘ es más que suficiente para esto.asort()
también tiene la mucho más útilsorted_in
, para permitirle simplemente definir un orden parafor (i in array)
para visite los elementos de la matriz; consulte gnu.org/software/gawk/manual/gawk.html#Controlling-Scanning. estoy de acuerdo en que solo conectar a UNIX Sin embargo, es más eficiente para este problema.