Сортировка нескольких ключей с помощью Unix sort

137

У меня есть потенциально большие файлы, которые нужно отсортировать по 1-n ключам. Некоторые из этих ключей могут быть числовыми, а некоторые - нет. Это столбчатый файл с фиксированной шириной, поэтому разделителей нет.

Есть ли хороший способ сделать это с помощью сортировки Unix? С одним ключом это так же просто, как использовать '-n'. Я прочитал справочную страницу и немного поискал в Google, но не нашел хорошего примера. Как бы я пошел для достижения этой цели?

Примечание: я исключил Perl из-за потенциального размера файла. Это было бы последнее средство.

Крис Клоберданз
источник
Одна или две строки примера данных были бы действительно полезны для создания примера командной строки. Кроме того, ключи "1-n" означают, что вам нужно сортировать по переменному количеству ключей? Делать это без сценариев будет весело ...
Кен Джентл
У меня есть PHP-оболочка вокруг команды сортировки, чтобы включить функцию 1-n.
Крис Клоберданц

Ответы:

69

Используйте -kопцию (или --key=POS1[,POS2]). Он может появляться несколько раз, и каждый ключ может иметь глобальные параметры (например, nдля числовой сортировки).

Кен Нежный
источник
7
На странице справки по сортировке: «POS - это F [.C] [OPTS], где F - номер поля, а C - позиция символа в поле; оба - начало 1». Смотрите man-страницу для полной документации.
Адам Розенфилд
49
Также посмотрите ответ Андраса, если вы не хотите сходить с ума.
Рон
1
Оба комментария выше точны и аддитивны. Спасибо, господа.
Кен Нежный
314

Будьте осторожны, хотя:

Если вы хотите отсортировать файл в основном по полю 3, а во вторую очередь по полю 2, вы хотите это:

sort -k 3,3 -k 2,2 < inputfile

Не это: sort -k 3 -k 2 < inputfile сортирует файл по строке от начала поля 3 до конца строки (что потенциально уникально).

-k, --key=POS1[,POS2]     start a key at POS1 (origin 1), end it at POS2
                          (default end of line)
Андраш
источник
8
Жизнь меняется. Спасибо.
Давидтбернал
2
Упс! Теперь я должен исправить скрипт, потому что раньше я видел только первый ответ выше ... хорошо, что я еще не зависел от вывода скрипта ....
Wildcard
Ницца! Теперь, что если я хочу, чтобы fleld 3 был отсортирован по номерам и обратно, тогда как поле 2 должно быть отсортировано не по номерам, а в обычном порядке (по возрастанию)? :)
Арун
2
@Arun POS объясняется в конце справочной страницы. Вы просто добавляете опции заказа к номеру поля следующим образом:sort -k 3,3nr -k 2,2
andras
1
Aargh. Какой -k2должен быть нелогичный интерфейс: -k2,2запятая -k2,должна быть «магический конец строки по умолчанию или что-то еще».
android.weasel
94

Опция -k - это то, что вы хотите.

-k 1.4,1.5n -k 1.14,1.15n

Будет использовать позиции символов 4-5 в первом поле (это все одно поле для фиксированной ширины) и числовой сортировки в качестве первого ключа.

Второй ключ будет также символами 14-15 в первом поле.

(редактировать)

Пример (все, что у меня есть, это DOS / Cygwin Handy):

dir | \cygwin\bin\sort.exe -k 1.4,1.5n -k 1.40,1.60r

для данных:

12/10/2008  01:10 PM         1,564,990 outfile.txt

Сортирует список каталогов по номеру месяца (поз. 4-5), а затем по имени файла (поз. 40-60) в обратном порядке. Поскольку вкладок нет, все поле 1 нужно отсортировать.

Клинтон Пирс
источник
Это только одно поле, если во входных данных нет пробелов. Тем не менее, ваш пример полезен.
Джонатан Леффлер
Исправление: если во входных данных нет / tabs /. В выводе команды DOS 'dir' нет вкладок.
Клинтон Пирс
Примеры того, как использовать опции (числовые, обратные), чрезвычайно полезны, так как практически невозможно узнать, как их использовать, просто на странице руководства, а другие ответы не упоминали об этом. Я бы хотел +2 за это. ;)
MSB
22

Здесь можно отсортировать различные столбцы в CSV-файле по числовому и словарному порядку, столбцы 5 и после по словарному порядку.

~/test>sort -t, -k1,1n -k2,2n -k3,3d -k4,4n -k5d  sort.csv
1,10,b,22,Ga
2,2,b,20,F
2,2,b,22,Ga
2,2,c,19,Ga
2,2,c,19,Gb,hi
2,2,c,19,Gb,hj
2,3,a,9,C

~/test>cat sort.csv
2,3,a,9,C
2,2,b,20,F
2,2,c,19,Gb,hj
2,2,c,19,Gb,hi
2,2,c,19,Ga
2,2,b,22,Ga
1,10,b,22,Ga

Обратите внимание, что -k1,1n означает числовое значение, начинающееся в столбце 1 и заканчивающееся в столбце 1. Если бы я сделал это ниже, он бы объединял столбцы 1 и 2, в результате чего 1,10 сортировался бы как 110

~/test>sort -t, -k1,2n -k3,3 -k4,4n -k5d  sort.csv
2,2,b,20,F
2,2,b,22,Ga
2,2,c,19,Ga
2,2,c,19,Gb,hi
2,2,c,19,Gb,hj
2,3,a,9,C
1,10,b,22,Ga
EdW
источник
1
Это лучший ответ, потому что он показывает, как использовать разные переключатели для разных столбцов
xaxa
12

Я верю в вашем случае что-то вроде

sort -t@ -k1.1,1.4 -k1.5,1.7 ... <inputfile

будет работать лучше. @ - это разделитель полей, убедитесь, что это символ, который нигде не отображается. тогда ваш вход считается состоящим из одного столбца.

Редактировать: по-видимому, clintp уже дал аналогичный ответ, извините. Как он указывает, флаги 'n' и 'r' могут быть добавлены к каждой опции -k ....

Донг Хун
источник
Несмотря на то, что разделителем по умолчанию, соответствующим документу gnu.org/software/coreutils/manual/html_node/…, является пробел, иногда количество полей не соответствует ожидаемому. Возможно, как уже говорили другие, из-за настройки локали LC_CTYPE. Если есть сомнения, считайте с начала строки!
Брэд Дре
5

Обратите внимание, что может также потребоваться стабилизировать сортировку с помощью -sпереключателя, чтобы строки с одинаковым ранжированием также сохраняли свой исходный относительный порядок в выходных данных.

рон
источник
2

Я просто хочу добавить несколько советов, когда вы используете сортировку, будьте осторожны с локалью, которая влияет на порядок сравнения ключей. Я обычно явно использую LC_ALL = C, чтобы сделать локаль тем, что я хочу.

jianpx
источник
LC_ALL = C также может привести к значительному ускорению!
Мат Келси