ordenar por valor hexadecimal


14

Usando coreutils sort, ¿cómo puedo ordenar numéricamente por un valor hexadecimal (campo)? Estaba esperando algo en la línea de

sort -k3,3x file_to_sort

sin embargo, tal xno existe.

Editar: La mejor solución que se me ocurrió hasta ahora es:

{ echo ibase=16; cut -d' ' -f3 file_to_sort; } |
  bc | paste -d: - file_to_sort | sort -t: -k1,1n | cut -d: -f2-

donde cut -d' ' -f3aísla el campo de búsqueda (esto es -k3,3, esto puede variar, por supuesto), y bcrealiza la conversión a decimal (requiere mayúscula hexadecimal, sin 0xprefijo, que coincida con mi caso). Luego unir, ordenar y dividir columnas.


-k3,3? ¿Tienes nubers hexagonales mirando con 0x y todos de la misma longitud? No hay mezcla de mayúsculas / minúsculas? En caso afirmativo, deben ordenar correctamente cuando se interpretan como cadenas. ¿Quizás pueda mostrarnos algunos datos de ejemplo?

@yeti: Desafortunadamente no.
stefan

Respuestas:


5

Una solución en perl:

$ perl -anle '
    push @h, [$F[-1],$_];
    END {
        print for map  { $_->[0] }
                  sort { $a->[1] <=> $b->[1] }
                  map  { [$_->[1],hex($_->[0])] } @h;
    }
' file
4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12

Explicación

  • Mientras procesamos el archivo, creamos una matriz de matriz @h, cada uno de sus elementos es una referencia de matriz [$F[-1],$_], con el primer elemento es el valor hexadecimal para comparar, y el segundo elemento es la línea completa.

  • En ENDbloque, usamos la transformación de Schwartz :

    • Con cada elemento de @h, crear una matriz anónima, contiene la línea completa ( $_->[1]el segundo elemento de cada referencia de matriz @h) y el valor hexadecimal para compararhex($_->[0])]

    • Ordenar por encima de la base de la matriz en el valor hexadecimal $a->[1] <=> $b->[1]

    • Obtenga el primer elemento de cada referencia de matriz en una matriz ordenada y map { $_->[0] } luego imprima el resultado.

Actualizar

Con la sugerencia de @Joseph R, sin usar la Transformación Schwartzian:

$ perl -anle '
    push @h, [hex($F[-1]),$_];
    END {
        print $_->[1] for
            sort { $a->[0] <=> $b->[0] } @h;
    }
' file

Actualización 2

Después de leer el comentario de stefan, creo que esto puede llamar direct:

$ perl -e '
    print sort {hex((split(/\s+/,$a))[-1]) <=> hex((split(/\s+/,$b))[-1])} <>;
' file
4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12

+1 pero ¿por qué no solo print for sort { hex $a->[-1] <=> hex $b->[-1] } @h:? El hexoperador no es lo suficientemente caro como para justificar un Schwartzian, ¿no?
Joseph R.

@JosephR .: Quizás, pero un Schwartzian es más flexible y funciona en todos los casos. Creo que podemos tener otra solución calculando el valor hexadecimal mientras se procesa, actualizaré mi respuesta pronto.
Cuonglm

Solución genial No sabía que este patrón tenía un nombre: decorar-ordenar-decorar. Ver mi comentario arriba.
stefan

@stefan: ver mi respuesta actualizada.
Cuonglm

@Gnouc: sí, su segunda actualización califica definitivamente como wrt directo. Mi imaginación inicial.
stefan

6

Yo uso este ejemplo de datos:

1 hdh d12
2 ukr 9f
3 ezh ae
4 jjk 7
5 hhf 25

La idea es crear una nueva versión de estos datos con el campo de clasificación en forma decimal. Es decir, lo awkconvierte, lo antepone a cada línea, el resultado se ordena y, como último paso, se elimina el campo agregado:

awk '{val="0x" $3; sub("^0x0x","0x",val); print strtonum(val),$0 ;}' file | 
  sort -n | 
  sed 's/^[^ ]* //'

Lo que da como resultado esta salida:

4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12

1
Gracias, una solución genial. Lamento no haber publicado mi edición anteriormente, sigue un enfoque similar usando cortar + pegar. Sin embargo, esperaba una solución más directa ...
stefan

@stefan ¿Qué cuenta como "directo"? ¿La solución tiene que usar sort?
Joseph R.

@Joseph "¿Qué cuenta como" directo "?" Es la pregunta correcta. Básicamente, todas las soluciones hasta ahora (las de Hauke, Gnouc a continuación y las mías) hacen algo similar: decodificar el valor hexadecimal, adjuntar el resultado a las líneas, ordenar por él y eliminarlo. Estaba buscando algo que no usara el patrón decorar-ordenar-decorar . Ambas soluciones son superiores a las mías, ya que trabajan en una tubería. Elegí este porque personalmente prefiero usar awk (el martillo más pequeño) que Perl para este tipo de tarea.
stefan

He movido mi elección de una respuesta al # 3 a continuación, debido a la segunda actualización de Gnouc.
stefan

1

Entrada

$ cat /tmp/input
0x45 aaa 333
0x50 dd 33
0x4 bbbb 444
0x456 cc 22
0x5 eee 1111

Ordenar un revestimiento

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1 | cut -f2- -d' '
0x4 bbbb 444
0x5 eee 1111
0x45 aaa 333
0x50 dd 33
0x456 cc 22

Ordenar paso a paso

Paso 1: agregue una nueva primera columna con la representación decimal del número hexadecimal.

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input 
69 0x45 aaa 333
80 0x50 dd 33
4 0x4 bbbb 444
1110 0x456 cc 22
5 0x5 eee 1111

Paso 2: Ordena las líneas numéricamente en el primer campo.

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1
4 0x4 bbbb 444
5 0x5 eee 1111
69 0x45 aaa 333
80 0x50 dd 33
1110 0x456 cc 22

Paso 3: eliminar la primera columna.

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1 | cut -f2- -d' '
0x4 bbbb 444
0x5 eee 1111
0x45 aaa 333
0x50 dd 33
0x456 cc 22

0

adaptado de: http://www.unix.com/302548935-post6.html?s=b4b6b3ed50b6831717f6429113302ad6

: archivo a ordenar:

6F993B
954B29
A23F2F
BFA91D
C68C15
8F322F
5A6D40
6D512C
9D9D63
B4B823
A0641C
A79716
A18518

Mando:

awk '{printf("%050s\t%s\n", toupper($0), $0)}' file-to-sort | LC_COLLATE=C sort -k1,1 | cut -f2

Salida:

C68C15
BFA91D
B4B823
A79716
A23F2F
A18518
A0641C
9D9D63
954B29
8F322F
6F993B
6D512C
5A6D40

- donde el toupper ($ 0) "actualiza" las letras minúsculas para que se ordenen primero (¿no está seguro de que sea necesario?)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.