сортировать по шестнадцатеричному значению

14

Используя coreutils sort, как я могу отсортировать численно по шестнадцатеричному значению (поле)? Я ожидал что-то вроде

sort -k3,3x file_to_sort

однако такого xне существует.

Изменить: лучшее решение, которое я придумал, это:

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

где cut -d' ' -f3изолирует поле поиска (это -k3,3- это, конечно, может отличаться) и bcвыполняет преобразование в десятичное число (требуется шестнадцатеричный регистр в верхнем регистре без 0xпрефикса, соответствующий моему регистру). Затем я объединяю, сортирую и разделяю столбцы.

Штефана
источник
-k3,3? У вас есть шестигранные нуберы, начиная с 0x и все одинаковой длины? Нет сочетания прописных и строчных букв? Если да, они должны сортироваться правильно, когда интерпретируются как строки. Может быть, вы можете показать нам пример данных?
@yeti: к сожалению нет.
Стефан
Запрос функции: lists.gnu.org/archive/html/coreutils/2017-08/msg00035.html
Сиро Сантилли 新疆 改造 中心 法轮功 六四 事件

Ответы:

5

Решение в 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

объяснение

  • При обработке файла мы создаем массив массива @h, каждый его элемент является ссылкой на массив [$F[-1],$_], первый элемент - это шестнадцатеричное значение для сравнения, а второй элемент - целая строка.

  • В ENDблоке мы используем преобразование Шварца :

    • С каждым элементом @hсоздайте анонимный массив, содержащий всю строку ( $_->[1]второй элемент каждого массива ref in @h) и шестнадцатеричное значение для сравнения.hex($_->[0])]

    • Сортировать выше массива на основе шестнадцатеричного значения $a->[1] <=> $b->[1]

    • Получить первый элемент каждого массива ref в отсортированном массиве, а map { $_->[0] } затем вывести результат.

Обновить

С предложением @Joseph R, без использования преобразования Шварца:

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

Обновление 2

Прочитав комментарий Стефана, я думаю, что это может вызвать 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
источник
+1 , но почему бы не просто: print for sort { hex $a->[-1] <=> hex $b->[-1] } @h? hexОператор вряд ли достаточно дорого , чтобы оправдать Шварц, не так ли?
Джозеф Р.
@JosephR .: Может быть, но Шварцян более гибок и работает во всех случаях. Я думаю, что у нас может быть другое решение путем вычисления шестнадцатеричного значения во время обработки, скоро обновлю мой ответ.
cuonglm
Классное решение. Не знал, что этот шаблон имеет имя: украшать-сортировать-украшать. Смотрите мой комментарий выше.
Стефан
@stefan: см. мой обновленный ответ.
cuonglm
@Gnouc: да, ваше второе обновление определенно считается прямым. мое первоначальное воображение.
Стефан
6

Я использую этот пример данных:

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

Идея состоит в том, чтобы создать новую версию этих данных с полем сортировки в десятичной форме. Т.е. awkпреобразует его, добавляет к каждой строке, результат сортируется, и в качестве последнего шага добавленное поле удаляется:

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

Что приводит к такому выводу:

4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12
Хауке Лагинг
источник
1
Спасибо, довольно классное решение. Извините, что я не опубликовал свое редактирование ранее, он использует аналогичный подход, используя cut + paste. Я надеялся на более прямое решение, хотя ...
Стефан
@stefan Что считается "прямым"? Нужно ли использовать решение sort?
Джозеф Р.
@ Джозеф «Что считается« прямым »?» - правильный вопрос. До сих пор все решения (Hauke, Gnouc ниже и мои) делают нечто похожее: декодируют шестнадцатеричное значение, прикрепляют результат к строкам, сортируют его и удаляют. Я искал что-то без использования декорации-сортировки-декорации . Оба решения превосходят мои в этой работе в конвейере. Я выбрал этот вариант, потому что лично я бы использовал awk (меньший молот), чем Perl для такого рода задач.
Стефан
Я переместил свой выбор ответа на # 3 ниже из-за второго обновления Gnouc.
Стефан
1

вход

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

Сортировка одного вкладыша

$ 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

Сортировка шаг за шагом

Шаг 1: Добавьте новый первый столбец с десятичным представлением шестнадцатеричного числа.

$ 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

Шаг 2: Сортируйте строки численно на первом поле.

$ 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

Шаг 3: Удалить первый столбец.

$ 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

адаптировано из: http://www.unix.com/302548935-post6.html?s=b4b6b3ed50b6831717f6429113302ad6

: Файл к сортировке:

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

Команда:

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

Выход:

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

- где toupper ($ 0) «обновляет» строчные буквы, чтобы они сначала сортировались (хотя не уверены, что это необходимо?)

r_alex_hall
источник