sortuj według wartości szesnastkowej

14

Używając coreutils sort, jak mogę sortować numerycznie według wartości szesnastkowej (pola)? Spodziewałem się czegoś podobnego

sort -k3,3x file_to_sort

jednak taki xnie istnieje.

Edycja: Najlepsze rozwiązanie, jakie do tej pory wymyśliłem, to:

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

gdzie cut -d' ' -f3izoluje pole wyszukiwania (to jest -k3,3- to może się oczywiście różnić) i bcwykonuje konwersję na dziesiętną (wymaga dużej liczby szesnastkowej, bez 0xprefiksu, pasującej do mojego przypadku). Następnie łączę, sortuję i dzielę kolumny.

Stefan
źródło
-k3,3? Czy masz nubery sześciokątne wpatrujące się w 0x i wszystkie tej samej długości? Brak połączenia wielkich / małych liter? Jeśli tak, powinny być odpowiednio posortowane, gdy są interpretowane jako łańcuchy. Może możesz nam pokazać przykładowe dane?
@yeti: Niestety nie.
Stefan
Żądanie funkcji: lists.gnu.org/archive/html/coreutils/2017-08/msg00035.html
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Odpowiedzi:

5

Rozwiązanie w 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

Wyjaśnienie

  • Podczas przetwarzania pliku tworzymy tablicę tablicy @h, każdy jego element jest odwołaniem do tablicy [$F[-1],$_], przy czym pierwszym elementem jest wartość szesnastkowa do porównania, a drugim elementem jest cała linia.

  • W ENDbloku używamy transformacji Schwartziana :

    • Z każdym elementem @hutwórz anonimową tablicę, zawiera całą linię ( $_->[1]drugi element każdej tablicy @h) i wartość szesnastkową do porównaniahex($_->[0])]

    • Sortuj powyżej podstawy tablicy na podstawie wartości szesnastkowej $a->[1] <=> $b->[1]

    • Pobierz pierwszy element każdego odwołania do tablicy posortowanej, map { $_->[0] } a następnie wydrukuj wynik.

Aktualizacja

Z sugestią @Josepha R, bez użycia Transformacji Schwartzian:

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

Aktualizacja 2

Po przeczytaniu komentarza Stefana myślę, że może to wywołać 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
źródło
+1, ale dlaczego nie tylko print for sort { hex $a->[-1] <=> hex $b->[-1] } @h:? hexOperator jest mało kosztowne wystarczająco, by uzasadnić Schwartzian, prawda?
Joseph R.
@JosephR .: Może, ale Schwartzian jest bardziej elastyczny i działa we wszystkich przypadkach. Myślę, że możemy mieć inne rozwiązanie, obliczając wartość szesnastkową podczas przetwarzania, wkrótce zaktualizuję moją odpowiedź.
cuonglm
Fajne rozwiązanie. Nie wiedziałem, że ten wzór ma nazwę: decorate-sort-undecorate. Zobacz mój komentarz powyżej.
Stefan
@stefan: zobacz moją zaktualizowaną odpowiedź.
cuonglm
@Gnouc: tak, twoja 2. aktualizacja ostatecznie kwalifikuje się jako bezpośrednie wrt. moja początkowa wyobraźnia.
stefan
6

Korzystam z tych przykładowych danych:

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

Chodzi o to, aby utworzyć nową wersję tych danych z polem sortowania w postaci dziesiętnej. Tj. awkKonwertuje go, dołącza do każdej linii, wynik jest sortowany, aw ostatnim kroku usuwane jest dodane pole:

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

Co daje w wyniku:

4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12
Hauke ​​Laging
źródło
1
Dzięki, całkiem fajne rozwiązanie. Przepraszam, że nie opublikowałem wcześniej mojej edycji, działa ona podobnie do metody cut + paste. Miałem jednak nadzieję na bardziej bezpośrednie rozwiązanie ...
Stefan
@stefan Co się liczy jako „bezpośrednie”? Czy rozwiązanie musi korzystać sort?
Joseph R.
@Joseph „Co liczy się jako„ bezpośrednie ”?” to właściwe pytanie. Zasadniczo wszystkie dotychczasowe rozwiązania (Hauke, Gnouc poniżej i moje) robią coś podobnego: odkoduj wartość szesnastkową, dołącz wynik do linii, posortuj go i usuń. Szukałem czegoś, co nie byłoby oparte na wzorze dekoruj, sortuj i dekoruj . Oba rozwiązania są lepsze od moich, ponieważ pracują w przygotowaniu. Wybrałem ten, ponieważ osobiście wolę używać do tego zadania awk (mniejszy młot) niż Perl.
Stefan
Wybrałem odpowiedź na nr 3 poniżej, z powodu drugiej aktualizacji Gnouca.
stefan
1

zaadaptowano z: http://www.unix.com/302548935-post6.html?s=b4b6b3ed50b6831717f6429113302ad6

: plik do sortowania:

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

Komenda:

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

Wynik:

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

- gdzie tupper (0 $) „aktualizuje” małe litery, aby najpierw posortowały (nie jesteś pewien, czy to konieczne?)

r_alex_hall
źródło
1

Wejście

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

Sortowanie jednej wkładki

$ 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

Sortowanie krok po kroku

Krok 1: Dodaj nową pierwszą kolumnę z dziesiętną reprezentacją liczby szesnastkowej.

$ 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

Krok 2: Sortuj linie numerycznie na pierwszym polu.

$ 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

Krok 3: Usuń pierwszą kolumnę.

$ 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
źródło