classificar por valor hexadecimal

14

Usando coreutils sort, como posso classificar numericamente por um valor hexadecimal (campo)? Eu estava esperando algo do tipo

sort -k3,3x file_to_sort

no entanto, tal xnão existe.

Edit: A melhor solução que eu vim até agora é:

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

onde cut -d' ' -f3isola o campo de pesquisa (isto é -k3,3- isso pode variar, é claro) e bcfaz a conversão para decimal (requer hexa maiúsculo, sem 0xprefixo, correspondente ao meu caso). Então eu ingresso, ordeno e divido colunas.

Stefan
fonte
-k3,3? Você tem hexadecimais com 0x e todos do mesmo comprimento? Nenhuma mistura de maiúsculas / minúsculas? Se sim, eles devem classificar corretamente quando interpretados como strings. Talvez você possa nos mostrar alguns dados de exemplo?
@ yeti: Infelizmente não.
Stefan
Solicitação de recurso: lists.gnu.org/archive/html/coreutils/2017-08/msg00035.html
Ciro Santilli escreveu:

Respostas:

5

Uma solução em 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

Explicação

  • Durante o processamento do arquivo, criamos uma matriz de matriz @h, cada um de seus elementos é uma referência de matriz [$F[-1],$_], com o primeiro elemento é o valor hexadecimal a ser comparado e o segundo elemento é a linha inteira.

  • No ENDbloco, usamos a transformação Schwartziana :

    • Com cada elemento de @h, crie uma matriz anônima, contém a linha inteira ( $_->[1]o segundo elemento de cada matriz ref in @h) e o valor hexadecimal para compararhex($_->[0])]

    • Classifique acima da base da matriz no valor hexadecimal $a->[1] <=> $b->[1]

    • Obtenha o primeiro elemento de cada matriz ref na matriz classificada map { $_->[0] } e imprima o resultado.

Atualizar

Com a sugestão de @Joseph R, sem usar a Schwartzian Transform:

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

Atualização 2

Depois de ler o comentário de stefan, acho que isso pode chamar 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
cuonglm
fonte
+1, mas por que não apenas print for sort { hex $a->[-1] <=> hex $b->[-1] } @h:? O hexoperador dificilmente é caro o suficiente para justificar um schwartziano, não é?
Joseph R.
@ Josephph .: Talvez, mas um Schwartzian é mais flexível e funciona em todos os casos. Acho que podemos ter outra solução, calculando o valor hexadecimal durante o processamento, atualizando minha resposta em breve.
cuonglm
Solução legal. Não sabia que esse padrão tinha um nome: decorate-sort-undecorate. Veja meu comentário acima.
Stefan
@stefan: veja minha resposta atualizada.
cuonglm
@Gnouc: sim, sua 2ª atualização se qualifica definitivamente como wrt direta. minha imaginação inicial.
Stefan
6

Eu uso esses dados de exemplo:

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

A idéia é criar uma nova versão desses dados com o campo de classificação na forma decimal. Ou seja, awkconverte-o, anexa-o a cada linha, o resultado é classificado e, na última etapa, o campo adicionado é removido:

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

O que resulta nesta saída:

4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12
Hauke ​​Laging
fonte
1
Obrigado, solução muito legal. Lamentamos não ter publicado minha edição anteriormente, segue uma abordagem semelhante usando recortar e colar. Eu estava esperando por uma solução mais direta ...
stefan
@stefan O que conta como "direto"? A solução precisa ser usada sort?
Joseph R.
@ Joseph “O que conta como" direto "?" É a pergunta certa. Basicamente, todas as soluções até agora (de Hauke, de Gnouc abaixo e as minhas) fazem algo semelhante: decodifique o valor hexadecimal, anexe o resultado às linhas, classifique-o e remova-o. Eu estava procurando por algo que não usasse o padrão decorar, classificar ou não decoração . Ambas as soluções são superiores às minhas, pois trabalham em um oleoduto. Eu escolhi este porque eu pessoalmente prefiro usar o awk (o martelo menor) do que o Perl para esse tipo de tarefa.
Stefan
Mudei minha opção de resposta para o item 3 abaixo, devido à segunda atualização do Gnouc.
Stefan
1

Entrada

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

Classificando um forro

$ 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

Classificando passo a passo

Etapa 1: adicione uma nova primeira coluna com a representação decimal do 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

Etapa 2: classifique as linhas numericamente no primeiro 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

Etapa 3: remova a primeira coluna.

$ 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
Arun Saha
fonte
0

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

: arquivo a classificar:

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

Comando:

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

Resultado:

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

- onde o toupper ($ 0) "atualiza" as letras minúsculas para que elas sejam classificadas primeiro (não tem certeza de que é necessário?)

r_alex_hall
fonte