Фильтрация текста - это процесс преобразований над входным потоком текста до того как он будет выдан в выходной поток. Хотя как входной, так и выходной поток могут поступать из файла, в системах Linux и UNIX фильтрация преимущественно осуществляется через конвейер команд, когда вывод одной команды связывается или перенаправляется на ввод следующей команды. Cейчас давайте взглянем на конвейер и простое перенаправление вывода с помощью операторов | и >.
Конвейер с помощью |Вспомним из предыдущего раздела, что интерпретатор оперирует с тремя стандартными потоками ввода/вывода:
stdin это стандартный поток ввода, через который поступает ввод командам.
stdout это стандратный выходной поток, через который команды выводят свой выход.
stderr это стандартный поток ошибок, через который выводятся ошибки в командах.
До сих пор, в этом руководстве, ввод представлял собой параметры, которые мы передавали командам, а вывод отображался на терминал. Многие команды обработки текста (фильтры) могут принимать входной поток, как из стандартного ввода, так и из файла. Чтобы использовать выход команды command1, как входной фильтр command2 вы должны соединить команды с помощью операции конвейерезации (|), как показано в Листинге 20.
Листинг 20. Связывание выхода command 1 со входом command2У любой из команд могут быть опции или аргументы, как вы увидите далее в этом разделе. Вы можете также использовать | для перенаправления вывода command2 в этом конвейере на вход другой команде, command3. Конструируя длинные конвейеры из команд, каждая из которых выполняет свою задачу, можно понять философию выполнения задач в Linux и UNIX. Также иногда вы будете видеть знак дефиса (-) вместо имени файла в качестве аргумента команды, в том значении, что ввод будет поступать из stdin, а не из файла.
Перенаправление вывода с помощью >риятно создавать конвейеры из нескольких команд и наблюдать результат на терминале, но бывают случаи, когда надо сохранить вывод в файл. Это можно сделать с помощью оператора перенаправления вывода (>).
В этой части руководства мы будем использовать небольшие файлы, поэтому давайте создадим каталог lpi103 и перейдем в него. Мы будем использовать > для перенаправления вывода echo в файл text1. Все это показано в Листинге 21. Заметим, что вывод не отображается на терминале, потому что он был перенаправлен в файл.
Листинг 21. Перенаправление вывода command 1 в файл[ian@echidna ian]$ mkdir lpi103
[ian@echidna ian]$ cd lpi103
[ian@echidna lpi103]$ echo -e "1 apple\n2 pear\n3 banana">text1
Теперь, имея в арсенале простые инструменты для создания конвейера и перенаправления, взглянем на наиболее распространенные утилиты обработки текста в UNIX и Linux. Этот раздел описывает некоторые простые возможности; чтобы узнать больше, смотрите соответсвующие страницы руководств по этим командам.
Cat, tac, od и splitВы создали файл test1, теперь вы захотите посмотреть его содержимое. Используйте команду cat (сокращение от catenate),чтобы отобразить содержимое файла на stdout. Листинг 22 проверяет содержимое файла, созданного выше.
Листинг 22. Вывод содержимого файла с помощью cat[ian@echidna lpi103]$ cat text1
1 apple
2 pear
3 banana
Команда cat принимает ввод из stdin, если вы не определите имя файла (или если напишите - как имя файла). Давайте используем эту возможность, а также перенаправление вывода, чтобы создать еще один текстовый файл как в Листинге 23.
Листинг 23. Создание текстового файла с помощью cat[ian@echidna lpi103]$ cat>text2
9 plum
3 banana
10 apple
В Листинге 23 cat продолжает читать из stdin до конца файла. Используйте комбинацию Ctrl-d (нажмите Ctrl, а затем нажмите d), чтобы послать сигнал конца файла. Такая же комбинация клавиш используется для выхода из bash. Заметим, что клавиша tab позволяет выровнить в столбец имена фруктов.
Случайно вам захотелось отобразить файл в обратном порядке. Разумеется, для этого тоже существует текстовый фильтр под названием tac (перестановка букв в cat). Листинг 24 отображает как новый файл text2, так и старый text1 в обратном порядке. Заметим, как просто соединились два файла.
Листинг 24. Реверсивное отображение с помощью tac[ian@echidna lpi103]$ tac text2 text1
10 apple
3 banana
9 plum
3 banana
2 pear
1 apple
Теперь положим, что вы отобразили два текстовых файла с помощью cat и tac и заметили разницу в выравнивании. Чтобы понять, почему это так, необходимо взглянуть на управляющие символы в файле. Так как они не имеют графического представления, то нам необходимо создать дамп файла в формате, который позволит вам найти и интерпретировать эти особые символы. Пакет текстовых утилит GNU включает команду od (или OctalDump) специально для этой цели.
У команды od есть несколько опций, как например -A для управления основанием смещений файла и -t для управления формой отображения содержимого файла. Основание может быть o, (восьмиричное - по умолчанию), d (десятичное), x (шестнадцатиричное) или n (смещения не отображаются). Вы можете отобразить файл в виде восьмиричном, шестнадцатиричном, десятичном, с плавающей точкой, ASCII с escape последовательностями или именоваными символами (nl для новой строки, ht для горизонтальной табуляции и так далее). В Листинге 25 представлены некоторые доступные форматы дампа файла text2.
Листинг 25. Дамп файлов с помощью od[ian@echidna lpi103]$ od text2
0000000 004471 066160 066565 031412 061011 067141 067141 005141
0000020 030061 060411 070160 062554 000012
0000031
[ian@echidna lpi103]$ od -A d -t c text2
0000000 9 \t p l u m \n 3 \t b a n a n a \n
0000016 1 0 \t a p p l e \n
0000025
[ian@echidna lpi103]$ od -A n -t a text2
9 ht p l u m nl 3 ht b a n a n a nl
1 0 ht a p p l e nl
Замечение:
Опция -A утилиты cat предоставляет альтернативный способ увидеть, где завершаются строки и символы табуляции. Для получения подробной информации смотрите man-страницы.
Если у вас есть знания об устройстве ЭВМ, то возможно вас заинетересует утилита hexdump, которая являюется частью другого набора утилит. Она здесь не рассматривается, поэтому обратитесь к man-страницам.
Наши тестовые файлы очень малы, но иногда требуется разбить большие файлы на несколько небольших. Например, вы хотите разбить большой файл на куски объемом с CD, чтобы их записать да CD и отправить по почте кому-нибудь, кто может создать для вас DVD. Команда split сделает это таким образом, что cat можно будет использовать для простого воссоздания файла. По умолчанию, файлы на выходе команды split имеют префикс 'x' в имени, за которым следует суффикс 'aa', 'ab', 'ac', ..., 'ba', 'bb' и так далее. Существуют опции, позволяющие изменять эти умолчания. Вы также можете управлять размером выходных файлов, как в строках, так и в байтах. В Листинге 26 происходит разделение двух текстовых файлов с разными префиксами в именах выходных файлов. Мы разделим text1 на файлы, содержащие не более двух строк, а text2 на файлы размером не более 18 байт. Затем мы используем cat для отображения различных частей, а также для отображения всего файла, используя подстановку, которая рассмотрена в разделе шаблоны и подстановки позже в этом руководстве.
Листинг 26. Разделение и воссоединение с помощью split и cat[ian@echidna lpi103]$ split -l 2 text1
[ian@echidna lpi103]$ split -b 18 text2 y
[ian@echidna lpi103]$ cat yaa
9 plum
3 banana
10[ian@echidna lpi103]$ cat yab
apple
[ian@echidna lpi103]$ cat y*
9 plum
3 banana
10 apple
Заметим, что получившийся файл yab не содержит символ новой строки, поэтому наше приглашение было смещено, когда мы использовали cat для его отображения.
Wc, head и tailCat и tac отображают файл целиком. Для маленьких файлов, с которыми имеем дело мы, это нормально, но предположим, что у вас большой файл. Для начала вы можете использовать команду wc (Word Count), чтобы посмотреть размер файла. Команда wc отображает число строк, слов и байт в файле. Вы также можете узнать число байт с помощью ls -l. Листинг 27 показывает длинный формат списка каталогов для двух файлов, а также вывод команды wc.
Листинг 27. Использование wc с текстовыми файлами [ian@echidna lpi103]$ ls -l text*
-rw-rw-r-- 1 ian ian 24 Sep 23 12:27 text1
-rw-rw-r-- 1 ian ian 25 Sep 23 13:39 text2
[ian@echidna lpi103]$ wc text*
3 6 24 text1
3 6 25 text2
6 12 49 total
Различные опции позволяют вам контролировать вывод команды wc илиотображать другую информацию, как например максимальная длина строки. Более подробно написано в man-страницах.
Две команды позволяют вам отобразить как начало (head) так и конец файла (tail). Это команды соответственно head и tail. Их можно использовать как фильтры, или же они могут принимать имя файла как аргумент. По умолчанию они отображают первые (или последние) 10 строк файла или потока.В Листинге 28 использована команда dmesg для отображения сообщений о загрузке совместно с wc, tail и head чтобы узнать, что всего имеется 177 сообщений, затем отображаются последние 10 строк, и, наконец, отображаются шесть сообщений, начиная с 15 от конца. Некоторые строки были обрезаны в этом выводе (об этом свидетельствует ...).
Листинг 28. Использование wc, head и tail для отображения загрузочных сообщений[ian@echidna lpi103]$
[ian@echidna lpi103]$ dmesg | wc
177 1164 8366
[ian@echidna lpi103]$ dmesg | tail
i810: Intel ICH2 found at IO 0x1880 and 0x1c00, MEM 0x0000 and ...
i810_audio: Audio Controller supports 6 channels.
i810_audio: Defaulting to base 2 channel mode.
i810_audio: Resetting connection 0
ac97_codec: AC97 Audio codec, id: ADS98 (Unknown)
i810_audio: AC'97 codec 0 Unable to map surround DAC's (or ...
i810_audio: setting clocking to 41319
Attached scsi CD-ROM sr0 at scsi0, channel 0, id 0, lun 0
sr0: scsi3-mmc drive: 0x/32x writer cd/rw xa/form2 cdda tray
Uniform CD-ROM driver Revision: 3.12
[ian@echidna lpi103]$ dmesg | tail -n15 | head -n 6
agpgart: Maximum main memory to use for agp memory: 941M
agpgart: Detected Intel i845 chipset
agpgart: AGP aperture is 64M @ 0xf4000000
Intel 810 + AC97 Audio, version 0.24, 13:01:43 Dec 18 2003
PCI: Setting latency timer of device 00:1f.5 to 64
i810: Intel ICH2 found at IO 0x1880 and 0x1c00, MEM 0x0000 and ...
Другим популярным использованием tail является слежение за файлом с помощью опции -f, обычно построчно. Это может полезным, если у вас есть фоновый процесс, который генерирует вывод в файл, и вы хотите проверить, что он сделал. В этом режиме tail будет работать, пока вы не прекратите его работу (с помощью Ctrl-c), отображая строки по мере того, как они будут поступать в файл.
Expand, unexpand и trКогда мы создали файлы text1 и text2, то использовали в text2 символы табуляции. Иногда требуется заменить символы табуляции на другие символы и наоборот. Команды expand и unexpand этим и занимаются. Опция -t в обеих командах позволяет установить шаг табуляции. Таким образом, каждый символ табуляции заменяется на этот шаг. В Листинге 29 показано, как заменить символы табуляции в text2 на пробелы, а также странная последовательность expand и unexpand которая переупорядочивает текст в text2.
Листинг 29. Использование expand и unexpand[ian@echidna lpi103]$ expand -t 1 text2
9 plum
3 banana
10 apple
[ian@echidna lpi103]$ expand -t8 text2|unexpand -a -t2|expand -t3
9 plum
3 banana
10 apple
К сожалению, вы не можете использовать unexpand, чтобы заменить пробелы в text1 на символы табуляции, так как unexpand необходимо по крайней мере два пробела для преобразования их в символ табуляции. Однако вы можете использовать команду tr которая переводит символы из одного набора (set1) в соответствующие символы другого набора(set2). В Листинге 30 показано, как использовать tr, чтобы преобразовать пробелы в символы табуляции. Так как tr это фильтр, то входные данные для него вы генерируете с помощью команды cat.Этот пример также иллюстрирует применение - для обозначения стандартного ввода в cat.
Листинг 30. Использование expand и unexpand[ian@echidna lpi103]$ cat text1 |tr ' ' '\t'|cat - text2
1 apple
2 pear
3 banana
9 plum
3 banana
10 apple
Если вы не уверены в том, что происходит в последних двух примерах, то наберите od, чтобы проверить каждую стадию конвейера; например
cat text1 |tr ' ' '\t' | od -tc
Pr, nl и fmtКоманда pr используется для форматирования файлов перед печатью. Заголовок по умолчанию включает имя файла и даты и время создания файла, а также номер страницы и двух пустых строк сносок. Когда выходной поток создается из нескольких файлов или из входного потока, то текущая дата и время появляются вместо имени файла и даты создания. Вы можете напечатать файлы параллельно в столбцах и управлять с помощью опций различными возможностями форматирования. Как обычно, смотрите man-страницы, чтобы узнать подробности.
Команда nl нумерует строки, что может быть полезно при печати файлов. Вы также можете нумеровать строки с помощью опции -n команды cat. На Листинге 31 показано как напечатать наш файл text 1, а затем как пронумеровать text2 и напечатать его параллельно с text1.