sort — сортировка строк текстовых файлов

We use cookies. Read the Privacy and Cookie Policy

Программа sort сортирует содержимое стандартного ввода или одного или нескольких файлов, указанных в командной строке, и записывает результаты в стандартный вывод. Применив тот же прием, который мы использовали совместно с командой cat, можно продемонстрировать обработку стандартного ввода.

[me@linuxbox ~]$ sort > foo.txt

c

b

a

[me@linuxbox ~]$ cat foo.txt

a

b

c

После запуска команды мы ввели буквы c, b и a, а затем признак конца файла с помощью комбинации CTRL+D. Затем просмотрели получившийся файл и увидели, что строки в нем отсортированы.

Поскольку sort может принимать несколько файлов в аргументах командной строки, существует возможность объединить множество файлов в один отсортированный файл. Например, если у вас имеется три файла и вам нужно объединить их в один отсортированный файл, это можно выполнить следующим образом:

sort file1.txt file2.txt file3.txt > final_sorted_list.txt

Программа sort имеет несколько интересных параметров. Их неполный список приводится в табл. 20.1.

Таблица 20.1. Часто используемые параметры команды sort

Параметр

Длинный параметр

Описание

-b

--ignore-leading-blanks

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

-f

--ignore-case

Выполнять сортировку без учета регистра символов

-n

--numeric-sort

Выполнять сортировку, опираясь на числовые значения строк. Этот параметр позволяет осуществлять сортировку в соответствии с числовыми значениями, а не по алфавиту

-r

--reverse

Сортировать в обратном порядке. Строки в результате будут следовать в порядке убывания, а не возрастания

-k

--key=поле1[,поле2]

Сортировать по ключевым полям, начиная с поля1 и заканчивая полем2, а не по всей строке

-m

--merge

Интерпретировать каждый аргумент как имя предварительно отсортированного файла. Позволяет объединить несколько файлов в общий результат без выполнения дополнительной сортировки

-o

--output=файл

Записать результат сортировки не в стандартный вывод, а в указанный файл

-t

--field-separator=символ

Определяет символ, разделитель полей. По умолчанию в качестве разделителя используются пробелы и символы табуляции

Имена большинства параметров из представленных выше говорят сами за себя, однако некоторые требуют дополнительных пояснений. Прежде всего рассмотрим параметр -n, используемый для сортировки по числовым значениям. Этот параметр позволяет сортировать строки по их числовым значениям. Продемонстрировать действие этого параметра можно на примере сортировки результатов команды du, чтобы определить каталог, занимающий больший объем дискового пространства. Обычно команда du выводит результаты, отсортированные по именам каталогов:

[me@linuxbox ~]$ du -s /usr/share/* | head

252 /usr/share/aclocal

96 /usr/share/acpi-support

8 /usr/share/adduser

196 /usr/share/alacarte

344 /usr/share/alsa

8 /usr/share/alsa-base

12488 /usr/share/anthy

8 /usr/share/apmd

21440 /usr/share/app-install

48 /usr/share/application-registry

В этом примере мы передали результаты по конвейеру программе head, чтобы ограничить число результатов первыми 10 строками. Мы можем изменить эту команду, добавив сортировку по числовым значениям, чтобы получить 10 самых объемных каталогов:

[me@linuxbox ~]$ du -s /usr/share/* | sort -nr | head

509940 /usr/share/locale-langpack

242660 /usr/share/doc

197560 /usr/share/fonts

179144 /usr/share/gnome

146764 /usr/share/myspell

144304 /usr/share/gimp

135880 /usr/share/dict

76508 /usr/share/icons

68072 /usr/share/apps

62844 /usr/share/foomatic

С помощью параметров -nr мы получили сортировку по числовым значениям в обратном порядке, в результате наибольшие значения оказались в начале списка. Такой способ сортировки стал возможен, потому что числовые значения находятся в начале каждой строки. Но как быть, если потребуется отсортировать строки по числовым значениям, находящимся в середине строки, как, например, в результатах команды ls -l?

[me@linuxbox ~]$ ls -l /usr/bin | head

total 152948

-rwxr-xr-x 1 root root 34824 2012-04-04 02:42 [

-rwxr-xr-x 1 root root 101556 2011-11-27 06:08 a2p

-rwxr-xr-x 1 root root 13036 2012-02-27 08:22 aconnect

-rwxr-xr-x 1 root root 10552 2011-08-15 10:34 acpi

-rwxr-xr-x 1 root root 3800 2012-04-14 03:51 acpi_fakekey

-rwxr-xr-x 1 root root 7536 2012-04-19 00:19 acpi_listen

-rwxr-xr-x 1 root root 3576 2012-04-29 07:57 addpart

-rwxr-xr-x 1 root root 20808 2012-01-03 18:02 addr2line

-rwxr-xr-x 1 root root 489704 2012-10-09 17:02 adept_batch

Забудем на время, что ls может сортировать свои результаты по размеру, и выполним сортировку с помощью sort.

[me@linuxbox ~]$ ls -l /usr/bin | sort -nr -k 5 | head

-rwxr-xr-x 1 root root 8234216 2012-04-07 17:42 inkscape

-rwxr-xr-x 1 root root 8222692 2012-04-07 17:42 inkview

-rwxr-xr-x 1 root root 3746508 2012-03-07 23:45 gimp-2.4

-rwxr-xr-x 1 root root 3654020 2012-08-26 16:16 quanta

-rwxr-xr-x 1 root root 2928760 2012-09-10 14:31 gdbtui

-rwxr-xr-x 1 root root 2928756 2012-09-10 14:31 gdb

-rwxr-xr-x 1 root root 2602236 2012-10-10 12:56 net

-rwxr-xr-x 1 root root 2304684 2012-10-10 12:56 rpcclient

-rwxr-xr-x 1 root root 2241832 2012-04-04 05:56 aptitude

-rwxr-xr-x 1 root root 2202476 2012-10-10 12:56 smbcacls

Программа sort часто вовлекается в обработку табличных данных, таких как результат команды ls выше. Если воспользоваться терминологией баз данных, об этой таблице можно сказать, что каждая строка — это запись и каждая запись состоит из множества полей, таких как атрибуты файла, счетчик ссылок, имя файла, размер файла и т.д. Программа sort способна обрабатывать поля по отдельности. Согласно той же терминологии баз данных, мы можем указать одно или несколько ключевых полей, которые должны использоваться как ключи сортировки. В примере, приведенном выше, мы добавили параметры n и r, чтобы выполнить сортировку по числовым значениям в порядке убывания, а также параметр -k с аргументом 5, чтобы указать, что сортировка должна выполняться по пятому полю.

Параметр очень интересен и обладает множеством любопытных свойств, но прежде чем приступить к их обсуждению, поговорим о том, как 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.

Далее попробуем отсортировать файл и посмотрим, что из этого получится:

[me@linuxbox ~]$ 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 использует в качестве ключа часть строки, начинающуюся с указанного поля и простирающуюся до конца строки.

Вот как выглядит синтаксис сортировки по нескольким ключам:

[me@linuxbox ~]$ 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 позволяет определять смещения внутри полей, чтобы в качестве ключей можно было использовать части полей:

[me@linuxbox ~]$ 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:

[me@linuxbox ~]$ 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 по седьмому полю (командная оболочка по умолчанию), используем такую команду:

[me@linuxbox ~]$ 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

gdm:x:106:114:Gnome Display Manager:/var/lib/gdm:/bin/false

hplip:x:104:7:HPLIP system user,,,:/var/run/hplip:/bin/false

klog:x:103:104::/home/klog:/bin/false

messagebus:x:108:119::/var/run/dbus:/bin/false

polkituser:x:110:122:PolicyKit,,,:/var/run/PolicyKit:/bin/false

pulse:x:107:116:PulseAudio daemon,,,:/var/run/pulse:/bin/false

Определив двоеточие как разделитель полей, мы смогли выполнить сортировку по седьмому полю.