Параметр очень интересен и обладает множеством любопытных свойств, но прежде чем приступить к их обсуждению, поговорим о том, как sort определяет поля. Рассмотрим очень простой текстовый файл, содержащий единственную строку с именем автора этой книги:
William Shotts
По умолчанию sort «видит» в этой строке два поля. Первое поле содержит последовательность символов William, второе — последовательность символов Shotts, то есть пробельные символы (пробелы и символы табуляции) интерпретируются как разделители полей, и эти разделители включаются в поле при выполнении сортировки.
Взглянув еще раз на любую строку в выводе нашей команды ls, можно сказать, что она содержит восемь полей и пятое поле хранит размер файла:
-rwxr-xr-x 1 root root 8234216 2012-04-07 17:42 inkscape
Для следующей серии экспериментов возьмем файл с историей выпуска новых версий трех популярных дистрибутивов Linux в период с 2006 по 2008 год. Каждая строка в файле содержит три поля: название дистрибутива, номер версии и дата выпускав формате ММ/ДД/ГГГГ:
SUSE 10.2 12/07/2006
Fedora 10 11/25/2008
SUSE 11.0 06/19/2008
Ubuntu 8.04 04/24/2008
Fedora 8 11/08/2007
SUSE 10.3 10/04/2007
Ubuntu 6.10 10/26/2006
Fedora 7 05/31/2007
Ubuntu 7.10 10/18/2007
Ubuntu 7.04 04/19/2007
SUSE 10.1 05/11/2006
Fedora 6 10/24/2006
Fedora 9 05/13/2008
Ubuntu 6.06 06/01/2006
Ubuntu 8.10 10/30/2008
Fedora 5 03/20/2006
С помощью текстового редактора (например, vim) введите эти данные и сохраните в файле с именем distros.txt.
Далее попробуем отсортировать файл и посмотрим, что из этого получится:
[[email protected] ~]$ sort distros.txt
Fedora 10 11/25/2008
Fedora 5 03/20/2006
Fedora 6 10/24/2006
Fedora 7 05/31/2007
Fedora 8 11/08/2007
Fedora 9 05/13/2008
SUSE 10.1 05/11/2006
SUSE 10.2 12/07/2006
SUSE 10.3 10/04/2007
SUSE 11.0 06/19/2008
Ubuntu 6.06 06/01/2006
Ubuntu 6.10 10/26/2006
Ubuntu 7.04 04/19/2007
Ubuntu 7.10 10/18/2007
Ubuntu 8.04 04/24/2008
Ubuntu 8.10 10/30/2008
У нас это почти получилось. Единственная проблема возникла с сортировкой номеров версий Fedora. Так как в лексикографическом смысле 1 предшествует 5, версия 10 оказалась вверху, тогда как версии 9 — внизу.
Чтобы исправить эту ошибку, выполним сортировку по нескольким ключам. Итак, нам нужно выполнить сортировку по первому полю в алфавитном порядке, а затем по второму полю в числовом порядке. Программа sort позволяет указать в командной строке несколько параметров -k, чтобы можно было определить несколько ключей сортировки. В действительности в ключ можно включать диапазон полей. Если диапазон не определен (как в примерах, приведенных выше), sort использует в качестве ключа часть строки, начинающуюся с указанного поля и простирающуюся до конца строки.
Вот как выглядит синтаксис сортировки по нескольким ключам:
[[email protected] ~]$ sort --key=1,1 --key=2n distros.txt
Fedora 5 03/20/2006
Fedora 6 10/24/2006
Fedora 7 05/31/2007
Fedora 8 11/08/2007
Fedora 9 05/13/2008
Fedora 10 11/25/2008
SUSE 10.1 05/11/2006
SUSE 10.2 12/07/2006
SUSE 10.3 10/04/2007
SUSE 11.0 06/19/2008
Ubuntu 6.06 06/01/2006
Ubuntu 6.10 10/26/2006
Ubuntu 7.04 04/19/2007
Ubuntu 7.10 10/18/2007
Ubuntu 8.04 04/24/2008
Ubuntu 8.10 10/30/2008
Здесь для ясности использовались имена параметров в длинной форме, однако с тем же успехом можно было бы передать параметры -k 1,1 -k 2n. В аргументе для первого экземпляра параметра ключа мы указали диапазон полей, входящих в первый ключ. Так как сортировка должна выполняться только по первому полю, мы указали диапазон 1,1, что означает: «начиная с поля 1 и заканчивая полем 1». Второму экземпляру мы передали аргумент 2n, который означает: «ключом сортировки является второе поле и сортировка выполняется в порядке числовых значений». В конце определения ключа допускаются однобуквенные имена параметров, они указывают на тип сортировки. Имена этих однобуквенных параметров совпадают с именами глобальных параметров программы sort: b (игнорировать начальные пробелы), n (числовая сортировка), r (сортировка в обратном порядке) и т.д.
Третье поле в списке содержит дату в формате, неудобном для сортировки. В компьютере даты обычно приводятся к виду ГГГГ-ММ-ДД, что упрощает сортировку в хронологическом порядке, но здесь используется американский формат ММ/ДД/ГГГГ. Как же тогда отсортировать этот список в хронологическом порядке?
К счастью, sort предоставляет такую возможность. Параметр --key позволяет определять смещения внутри полей, чтобы в качестве ключей можно было использовать части полей:
[[email protected] ~]$ sort -k 3.7nbr -k 3.1nbr -k 3.4nbr distros.txt
Fedora 10 11/25/2008
Ubuntu 8.10 10/30/2008
SUSE 11.0 06/19/2008
Fedora 9 05/13/2008
Ubuntu 8.04 04/24/2008
Fedora 8 11/08/2007
Ubuntu 7.10 10/18/2007
SUSE 10.3 10/04/2007
Fedora 7 05/31/2007
Ubuntu 7.04 04/19/2007
SUSE 10.2 12/07/2006
Ubuntu 6.10 10/26/2006
Fedora 6 10/24/2006
Ubuntu 6.06 06/01/2006
SUSE 10.1 05/11/2006
Fedora 5 03/20/2006
Добавив параметр -k 3.7, мы сообщили программе sort, что она должна использовать для сортировки ключ, начинающийся с седьмого символа в третьем поле, который соответствует началу года. Аналогично, параметры -k 3.1 и -k 3.4 определяют ключи сортировки по месяцу и дню месяца. Мы также добавили параметры n и r, чтобы выполнить числовую сортировку в обратном порядке. Параметр b добавлен для исключения начальных пробелов из поля с датой (число которых в разных строках отличается и тем самым влияет на результат сортировки).
В некоторых файлах в качестве разделителей используются символы, отличные от пробелов и символов табуляции; возьмем, к примеру, файл /etc/passwd:
[[email protected] ~]$ head /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
Поля в этом файле отделяются друг от друга символом двоеточия (:). Можно ли отсортировать содержимое этого файла с использованием ключевых полей? Программа sort поддерживает параметр -t для определения символа-разделителя полей. Чтобы отсортировать содержимое файла passwd по седьмому полю (командная оболочка по умолчанию), используем такую команду:
[[email protected] ~]$ sort -t ':' -k 7 /etc/passwd | head
me:x:1001:1001:Myself,,,:/home/me:/bin/bash
root:x:0:0:root:/root:/bin/bash
dhcp:x:101:102::/nonexistent:/bin/false