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.