355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Уильям Шоттс » Командная строка Linux » Текст книги (страница 18)
Командная строка Linux
  • Текст добавлен: 12 апреля 2017, 12:30

Текст книги "Командная строка Linux"


Автор книги: Уильям Шоттс


Жанр:

   

ОС и Сети


сообщить о нарушении

Текущая страница: 18 (всего у книги 30 страниц)

В некоторых файлах в качестве разделителей используются символы, отличные от пробелов и символов табуляции; возьмем, к примеру, файл /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

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

uniq – выявление или удаление повторяющихся строк

В сравнении с sort программа uniq более легковесна. Она решает, казалось бы, тривиальную задачу. Когда ей передается сортированный файл (в том числе и стандартный ввод), она удаляет повторяющиеся строки и выводит результат в стандартный вывод. Она часто используется в сочетании с sort для удаления повторяющихся строк.

ПРИМЕЧАНИЕ

Даже при том что uniq – инструмент, традиционный для Unix, который часто используется вместе с sort, GNU-версия sort поддерживает параметр -u, удаляющий повторяющиеся строки из сортированных результатов.

Давайте создадим текстовый файл для последующих экспериментов:

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

a

b

c

a

b

c

Не забудьте ввести CTRL+D, чтобы завершить ввод с клавиатуры. Если теперь применить uniq к нашему текстовому файлу, результат ничем не будет отличаться от оригинала; повторяющиеся записи никуда не исчезли:

[me@linuxbox ~]$ uniq foo.txt

a

b

c

a

b

c

Чтобы uniq действительно выполнила свою работу, исходные данные нужно сначала отсортировать:

[me@linuxbox ~]$ sort foo.txt | uniq

a

b

c

Это объясняется тем, что uniq удаляет повторяющиеся записи, только если они следуют друг за другом.

uniq имеет несколько параметров. Наиболее часто используемые из них перечислены в табл. 20.2.

В следующем примере используется параметр -c программы uniq для определения числа повторяющихся строк в исходном текстовом файле:

[me@linuxbox ~]$ sort foo.txt | uniq -c

      2 a

      2 b

      2 c

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

Параметр

Описание

–c

Вывести список повторяющихся строк, предваряя их числом найденных дубликатов

–d

Вывести только повторяющиеся, не уникальные строки

–f n

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

–i

Сравнивать строки без учета регистра символов

–s n

Пропустить n начальных символов в каждой строке

–u

Вывести только уникальные строки. Подразумевается по умолчанию

Нарезка и перетасовка текста

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

cut – удаление фрагментов из всех строк в файлах

Программа cut используется для извлечения фрагментов текста из строк и вывода их в стандартный вывод. Она может принимать имена файлов в аргументах или данные со стандартного ввода.

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

Таблица 20.3. Параметры команды cut для выбора фрагментов

Параметр

Описание

–c список_символов

Извлекает фрагмент строки, определяемый списком_символов. Список может включать один или несколько числовых диапазонов, разделенных запятыми

–f список_полей

Извлекает одно или несколько полей из строки, как определено аргументом список_символов. Список может включать одно или несколько полей или диапазонов полей, разделенных запятыми

–d символ_разделитель

В присутствии параметра -f в качестве разделителя полей используется символ_разделитель. По умолчанию поля должны отделяться друг от друга одним символом табуляции

–complement

Извлекает строку текста целиком, кроме фрагментов, определяемых параметром -c и/или -f

Как видите, программа cut не обладает особенной гибкостью. Она лучше всего подходит для извлечения фрагментов из текста, произведенного другими программами, а не человеком. Давайте вернемся к нашему файлу distros.txt и посмотрим, достаточно ли он «хорош» для программы cut. Если воспользоваться программой cat с параметром -A, можно увидеть, отвечает ли файл требованию в отношении использования символа табуляции в качестве разделителя полей.

[me@linuxbox ~]$ cat -A distros.txt

SUSE^I10.2^I12/07/2006$

Fedora^I10^I11/25/2008$

SUSE^I11.0^I06/19/2008$

Ubuntu^I8.04^I04/24/2008$

Fedora^I8^I11/08/2007$

SUSE^I10.3^I10/04/2007$

Ubuntu^I6.10^I10/26/2006$

Fedora^I7^I05/31/2007$

Ubuntu^I7.10^I10/18/2007$

Ubuntu^I7.04^I04/19/2007$

SUSE^I10.1^I05/11/2006$

Fedora^I6^I10/24/2006$

Fedora^I9^I05/13/2008$

Ubuntu^I6.06^I06/01/2006$

Ubuntu^I8.10^I10/30/2008$

Fedora^I5^I03/20/2006$

Похоже, что все в порядке: пробелы отсутствуют и поля разделены единственными символами табуляции. Поскольку вместо пробелов в файле используются символы табуляции, можно воспользоваться параметром -f для извлечения поля:

[me@linuxbox ~]$ cut -f 3 distros.txt

12/07/2006

11/25/2008

06/19/2008

04/24/2008

11/08/2007

10/04/2007

10/26/2006

05/31/2007

10/18/2007

04/19/2007

05/11/2006

10/24/2006

05/13/2008

06/01/2006

10/30/2008

03/20/2006

Так как поля в файле distros.txt разделены символами табуляции, их удобнее извлекать с помощью cut именно как поля, а не как группы символов. Когда поля разделяются символами табуляции, маловероятно, что строки будут содержать одно и то же число символов, из-за чего определение позиций символов в строках становится сложной или неразрешимой задачей. В примере, приведенном выше, мы смогли извлечь поля с датами, которые, к нашей удаче, все имеют одинаковую длину, поэтому теперь мы можем показать, как выполняется извлечение групп символов, для чего попробуем извлечь год из каждой строки:

[me@linuxbox ~]$ cut -f 3 distros.txt | cut -c 7-10

2006

2008

2008

2008

2007

2007

2006

2007

2007

2007

2006

2006

2008

2006

2008

2006

Применив cut второй раз к нашему списку, мы смогли извлечь символы в позициях с 7-й по 10-ю, которые соответствуют году в поле с датой. Форма записи 7-10 – это пример определения диапазона. Полное описание особенностей определения диапазонов находится на странице справочного руководства (man) для команды cut.

При работе с полями определим разделитель, отличающийся от символа табуляции. Следующий пример извлекает первое поле из файла /etc/passwd:

[me@linuxbox ~]$ cut -d ':' -f 1 /etc/passwd | head

root

daemon

bin

sys

sync

games

man

lp

mail

news

С помощью параметра -d мы определили, что роль разделителя полей будет играть символ двоеточия.

замена символов табуляции

Наш файл distros.txt идеально отформатирован для извлечения полей с использованием cut. Но что, если нам понадобится обработать файл, вырезая фрагменты по символам, а не по полям? Для этого нам нужно заменить символы табуляции в файле соответствующим числом пробелов. К счастью, в GNU-пакете coreutils имеется инструмент для этого – программа expand. Она может принимать имена файлов в аргументах или данные со стандартного ввода и выводить измененный текст в стандартный вывод.

Если обработать наш файл distros.txt программой expand, мы сможем использовать cut -c для извлечения любых диапазонов символов из файла. Например, с помощью следующей команды можно извлечь год выпуска из нашего файла со списком, применив cut для извлечения всех символов с 23-й позиции до конца строки:

[me@linuxbox ~]$ expand distros.txt | cut -c 23-

В состав пакета coreutils входит также программа unexpand, замещающая пробелы символами табуляции.

paste – слияние строк из файлов

Команда paste выполняет операцию, обратную команде cut. Вместо извлечения колонок текста из файла она добавляет одну или несколько колонок текста в файл. Для этого она читает содержимое нескольких файлов, комбинирует поля, найденные в них, и выводит результат в стандартный вывод. Подобно программе cut, paste принимает несколько файлов в аргументах и/или данные со стандартного ввода. Для демонстрации возможностей программы paste выполним небольшую хирургическую операцию с файлом distros.txt, чтобы получить список выпусков в хронологическом порядке.

Сначала применим команду sort, чтобы получить список дистрибутивов, отсортированный по дате выпуска, и сохраним результат в файле distros-by-date.txt:

[me@linuxbox ~]$ sort -k 3.7nbr -k 3.1nbr -k 3.4nbr distros.txt > distros-bydate.txt

Затем с помощью cut извлечем два первых поля (с именами дистрибутивов и номерами версий) и сохраним результат в файле distro-versions.txt:

[me@linuxbox ~]$ cut -f 1,2 distros-by-date.txt > distros-versions.txt

[me@linuxbox ~]$ head distros-versions.txt

Fedora           10

Ubuntu           8.10

SUSE             11.0

Fedora           9

Ubuntu           8.04

Fedora           8

Ubuntu           7.10

SUSE             10.3

Fedora           7

Ubuntu           7.04

В заключение этапа подготовки извлечем даты выпусков и сохраним их в файле distro-dates.txt:

[me@linuxbox ~]$ cut -f 3 distros-by-date.txt > distros-dates.txt

[me@linuxbox ~]$ head distros-dates.txt

11/25/2008

10/30/2008

06/19/2008

05/13/2008

04/24/2008

11/08/2007

10/18/2007

10/04/2007

05/31/2007

04/19/2007

Теперь у нас есть все необходимое. Чтобы завершить процедуру, с помощью paste добавим колонку с датами перед названиями и номерами версий дистрибутивов, создав хронологический список. Для этого достаточно просто вызвать paste и передать ей файлы в требуемом порядке.

[me@linuxbox ~]$ paste distros-dates.txt distros-versions.txt

11/25/2008       Fedora          10

10/30/2008       Ubuntu          8.10

06/19/2008       SUSE            11.0

05/13/2008       Fedora          9

04/24/2008       Ubuntu          8.04

11/08/2007       Fedora          8

10/18/2007       Ubuntu          7.10

10/04/2007       SUSE            10.3

05/31/2007       Fedora          7

04/19/2007       Ubuntu          7.04

12/07/2006       SUSE            10.2

10/26/2006       Ubuntu          6.10

10/24/2006       Fedora          6

06/01/2006       Ubuntu          6.06

05/11/2006       SUSE            10.1

03/20/2006       Fedora          5

join – объединение строк из двух файлов по общему полю

Программа join действует подобно paste, в том смысле, что она добавляет колонки в файл, но делает это по-своему. Операция join у многих ассоциируется с реляционными базами данных, где она объединяет записи из нескольких таблиц по общему ключевому полю. Программа join выполняет ту же операцию. Она объединяет данные из множества файлов, опираясь на общее ключевое поле.

Чтобы понять, как действует операция join в реляционной базе данных, представьте очень маленькую базу данных с двумя таблицами, по одной записи в каждой. Первая таблица, с именем CUSTOMERS, имеет три поля: номер клиента (CUSTNUM), имя клиента (FNAME) и фамилия клиента (LNAME):

CUSTNUM         FNAME   LNAME

=========       ======  ======

4681934         John    Smith

Вторая таблица, с именем ORDERS, имеет четыре поля: номер заказа (ORDERNUM), номер клиента (CUSTNUM), количество (QUAN) и пункт заказа (ITEM):

ORDERNUM        CUSTNUM         QUAN    ITEM

==========      =========       =====   ====

3014953305      4681934         1       Blue Widget

Обратите внимание, что обе таблицы имеют общее поле CUSTNUM. Это важно, так как оно устанавливает отношение между таблицами.

Применив операцию join, мы сможем объединить поля из двух таблиц, чтобы получить желаемый результат, например, для подготовки накладной. Проверяя совпадение значений в полях CUSTNUM обеих таблиц, операция join выдаст следующий результат:

FNAME   LNAME   QUAN    ITEM

======  ======  =====   ====

John    Smith   1       Blue Widget

Для демонстрации программы join нам понадобится пара файлов с общим ключом. Возьмем в качестве отправной точки файл distros-by-date.txt и из него сконструируем два дополнительных файла. Первый будет содержать даты выпусков (которые в этом примере будут играть роль общего ключа) и названия дистрибутивов:

[me@linuxbox ~]$ cut -f 1,1 distros-by-date.txt > distros-names.txt

[me@linuxbox ~]$ paste distros-dates.txt distros-names.txt > distros-key-names.txt

[me@linuxbox ~]$ head distros-key-names.txt

11/25/2008       Fedora

10/30/2008       Ubuntu

06/19/2008       SUSE

05/13/2008       Fedora

04/24/2008       Ubuntu

11/08/2007       Fedora

10/18/2007       Ubuntu

10/04/2007       SUSE

05/31/2007       Fedora

04/19/2007       Ubuntu

И второй – даты выпусков и номера версий:

[me@linuxbox ~]$ cut -f 2,2 distros-by-date.txt > distros-vernums.txt

[me@linuxbox ~]$ paste distros-dates.txt distros-vernums.txt > distros-keyvernums.txt

[me@linuxbox ~]$ head distros-key-vernums.txt

11/25/2008       10

10/30/2008       8.10

06/19/2008       11.0

05/13/2008       9

04/24/2008       8.04

11/08/2007       8

10/18/2007       7.10

10/04/2007       10.3

05/31/2007       7

04/19/2007       7.04

Теперь у нас есть два файла с общим ключом (поле «дата выпуска»). Здесь важно отметить, что файлы должны быть отсортированы по ключевому полю, чтобы программа join выдала правильный результат.

[me@linuxbox ~]$ join distros-key-names.txt distros-key-vernums.txt | head

11/25/2008 Fedora 10

10/30/2008 Ubuntu 8.10

06/19/2008 SUSE 11.0

05/13/2008 Fedora 9

04/24/2008 Ubuntu 8.04

11/08/2007 Fedora 8

10/18/2007 Ubuntu 7.10

10/04/2007 SUSE 10.3

05/31/2007 Fedora 7

04/19/2007 Ubuntu 7.04

Отметьте также, что по умолчанию в качестве разделителя полей во входных данных join использует символы табуляции, а в выводе – пробел. Такое поведение можно изменить с помощью параметров. За дополнительными подробностями обращайтесь к странице справочного руководства (man) для join.

Сравнение текста

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

comm – построчное сравнение двух сортированных файлов

Программа comm сравнивает два текстовых файла, показывая, какие строки в них уникальные, а какие – одинаковые. Для демонстрации создадим с помощью cat два почти идентичных файла:

[me@linuxbox ~]$ cat > file1.txt

a

b

c

d

[me@linuxbox ~]$ cat > file2.txt

b

c

d

e

Затем сравним эти два файла с помощью comm:

[me@linuxbox ~]$ comm file1.txt file2.txt

a

                b

                c

                d

        e

Как видите, comm произвела вывод в три колонки. Первая колонка содержит уникальные строки из первого файла, вторая – уникальные строки из второго файла, третья – строки, одинаковые в обоих файлах. Программа comm поддерживает параметры в формате -n, где n может быть числом 1, 2 или 3. При использовании эти параметры определяют номера колонок, вывод которых следует подавить. Например, чтобы вывести только одинаковые строки, нужно подавить вывод колонок 1 и 2:

[me@linuxbox ~]$ comm -12 file1.txt file2.txt

b

c

d

diff – построчное сравнение файлов

Подобно программе comm, diff используется для выявления различий между файлами. Однако diff намного более сложный инструмент, поддерживающий вывод во множестве форматов и способный обрабатывать сразу огромные коллекции файлов. Программа diff часто используется разработчиками программного обеспечения для исследования различий между разными версиями исходного программного кода, потому что позволяет рекурсивно обходить каталоги, которые часто называют деревьями исходного кода (source trees). Часто программа diff применяется для создания diff-файлов, или заплат (patches), которые могут использоваться другими программами, такими как patch (о которой рассказывается чуть ниже), для преобразования файлов из одной версии в другую.

Если применить diff к файлам из предыдущего примера, можно увидеть стиль вывода результатов ее работы по умолчанию: краткое описание различий между двумя файлами.

[me@linuxbox ~]$ diff file1.txt file2.txt

1d0

< a

4a4

> e

В формате по умолчанию каждой группе изменений предшествует команда изменения (табл. 20.4) в форме диапазон – операция – диапазон, описывающей позиции и типы изменений, которые нужно выполнить, чтобы преобразовать первый файл во второй.

Таблица 20.4. Команды изменения, генерируемые программой diff

Команда

Описание

r1ar2

Добавить строки, находящиеся в диапазоне r2 во втором файле, после строк в позиции r1 в первом файле

r1cr2

Изменить (заменить) строки в диапазоне r1 в первом файле строками в диапазоне r2 во втором файле

r1dr2

Удалить строки в диапазоне r1 в первом файле, которые находились бы в диапазоне r2 во втором файле

В этом формате любой диапазон представлен списком через запятую номеров начальной и конечной строки. Хотя этот формат используется по умолчанию (главным образом для совместимости со стандартом POSIX и обратной совместимости с традиционными версиями diff для Unix), он не так широко используется, как другие, дополнительные форматы. Два других формата, получивших большую популярность, – это контекстный формат и унифицированный формат.

При использовании контекстного формата (параметр -c) вывод выглядит так:

[me@linuxbox ~]$ diff -c file1.txt file2.txt

*** file1.txt    2012-12-23 06:40:13.000000000 -0500

– file2.txt    2012-12-23 06:40:34.000000000 -0500

***************

*** 1,4 ****

– a

  b

  c

  d

– 1,4 –

  b

  c

  d

+ e

Вывод начинается с имен двух файлов и времени последнего их изменения. Первый файл отмечается звездочками, а второй – дефисами. На протяжении всей оставшейся части листинга эти маркеры обозначают соответствующие им файлы. Далее следуют группы изменений, включая заданное по умолчанию число окружающих строк, определяющих контекст. Первая группа начинается со строки *** 1,4 ****, указывающей на строки с номерами с 1 по 4 в первом файле. Далее следует строка – 1,4 –, указывающая на строки с номерами с 1-го по 4-й во втором файле. Внутри группы изменений присутствуют строки, начинающиеся с одного из четырех индикаторов, перечисленных в табл. 20.5.

Таблица 20.5. Индикаторы изменений, генерируемые программой diff при использовании контекстного формата

Индикатор

Значение

(нет)

Строка показана для контекста. В ней отсутствуют различия между файлами

Строка удалена. Эта строка присутствует в первом файле и отсутствует во втором

+

Строка добавлена. Эта строка присутствует во втором файле и отсутствует в первом

!

Строка изменена. Выводятся две версии строки, каждая в соответствующем разделе внутри группы изменений

Унифицированный формат напоминает контекстный, но более компактный. Задается параметром -u:

[me@linuxbox ~]$ diff -u file1.txt file2.txt

– file1.txt    2012-12-23 06:40:13.000000000 -0500

+++ file2.txt    2012-12-23 06:40:34.000000000 -0500

@@ -1,4 +1,4 @@

–a

b

c

d

+e

Самое большое отличие между контекстным и унифицированным форматами – отсутствие повторяющихся контекстных строк, благодаря чему обеспечивается большая компактность унифицированного формата в сравнении с контекстным. В примере, приведенном выше, видны те же времена последнего изменения файлов, что и в контекстном формате, за которыми следует строка @@ -1,4 +1,4 @@. Она указывает номера строк в первом и во втором файлах, описываемых группой изменений. Далее следуют сами строки с тремя (по умолчанию) строками контекста. Каждая строка начинается с одного из трех возможных символов, значение которых описывается в табл. 20.6.

Таблица 20.6. Индикаторы изменений, генерируемые программой diff при использовании унифицированного формата

Индикатор

Значение

(нет)

Строка присутствует в обоих файлах

Строка отсутствует в первом файле

+

Строка присутствует только в первом файле

patch – применение diff-файла к оригиналу

Программа patch используется для применения изменений к текстовым файлам. Она принимает вывод программы diff и обычно используется для преобразования старых версий файлов в более новые. Рассмотрим один известный пример. Ядро Linux разрабатывается большой, свободно организованной группой разработчиков, от которых неиссякаемым потоком идут небольшие изменения в исходном коде. Ядро Linux включает миллионы строк программного кода, но изменения, присылаемые одним разработчиком за один раз, очень невелики. Разработчикам нет смысла пересылать все дерево исходных текстов ядра всякий раз, когда вносится небольшое изменение. Вместо этого они присылают diff-файлы. Эти файлы описывают различия между предыдущей версией ядра и новой, включающей изменения разработчика. Другой разработчик, получивший такое изменение, использует программу patch, позволяющую применить предложенное изменение к своему дереву исходных текстов. Использование пары программ diff/patch дает два важных преимущества:

• diff-файл очень невелик в сравнении с полным деревом исходных текстов;

• diff-файл наглядно показывает произведенные изменения, что позволяет экспертам быстро применить эти изменения и оценить их.

Разумеется, пару diff/patch можно применять к любым текстовым файлам, не только к исходному коду. Эти программы с таким же успехом можно применять к конфигурационным файлам или другому тексту.

Чтобы подготовить diff-файл для последующего его применения программой patch, документация GNU предлагает использовать diff, как показано ниже:

diff -Naur старый_файл новый_файл > diff_файл

где старый_файл и новый_файл могут быть одиночными файлами или каталогами. Параметр r поддерживает рекурсивный обход вложенных подкаталогов.

Получив diff-файл, его можно применить к старому файлу, чтобы получить новый:

patch < diff_файл

Продемонстрируем это на примере нашего тестового файла:

[me@linuxbox ~]$ diff -Naur file1.txt file2.txt > patchfile.txt

[me@linuxbox ~]$ patch < patchfile.txt

patching file file1.txt

[me@linuxbox ~]$ cat file1.txt

b

c

d

e

В этом примере мы создали diff-файл с именем patchfile.txt и затем воспользовались программой patch, чтобы применить его (наложить «заплату»). Обратите внимание, что нам не пришлось указывать целевой файл, потому что diff-файл (в унифицированном формате) уже содержит имена файлов в заголовке. После наложения «заплаты» содержимое file1.txt точно соответствует содержимому file2.txt.

Программа patch имеет большое число параметров, а кроме того, существует множество вспомогательных программ, которые помогут в правке «заплат» (diff-файлов).

Редактирование на лету

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

tr – перекодирование или удаление символов

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

[me@linuxbox ~]$ echo «lowercase letters» | tr a-z A-Z

LOWERCASE LETTERS

Как видите, tr принимает исходные данные со стандартного ввода и выводит результаты в стандартный вывод. tr принимает два аргумента: множество символов, подлежащих преобразованию, и соответствующее множество символов, в которые должны превратиться преобразуемые символы. Множества символов можно выразить тремя способами:

• в виде списка-перечисления, например ABCDEFGHIJKLMNOPQRSTUVWXYZ;

• в виде диапазона символов, например A-Z. Обратите внимание, что этому способу сопутствуют те же проблемы, что наблюдаются в других программах (из-за разного порядка алфавитной сортировки в разных регионах), и потому он должен использоваться с осторожностью;

• в виде классов символов POSIX, например [:upper:].

В большинстве случаев множества символов должны иметь одинаковую длину; что вполне допустимо в случае, если первое множество оказывается больше второго. Это может пригодиться, например, если существует необходимость преобразования нескольких символов в один:

[me@linuxbox ~]$ echo «lowercase letters» | tr [:lower:] A

AAAAAAAAA AAAAAAA

Кроме перекодирования tr позволяет просто удалять символы из входного потока. Выше в этой главе мы обсуждали проблему преобразования текстовых файлов в формате MS-DOS в текст в формате Unix. Для такого преобразования достаточно просто удалить символы возврата каретки в конце каждой строки. Эту операцию можно выполнить с помощью tr:

tr -d 'r' < файл_dos > файл_unix

где файл_dos – это файл, подлежащий преобразованию, а файл_unix – результат. В этой форме команды используется экранированная последовательность r, представляющая символ возврата каретки. Чтобы увидеть полный список последовательностей и классов символов, поддерживаемых программой tr, попробуйте

[me@linuxbox ~]$ tr –help

ROT13: не самый надежный способ шифрования

Одно забавное применение команды tr – шифрование текста по алгоритму ROT13. ROT13 – тривиальный тип шифрования, основанный на простом подстановочном шифре. Шифрованием назвать этот алгоритм можно только с большой натяжкой, скорее это алгоритм обфускации (запутывания) текста. Он используется иногда для запутывания потенциально уязвимого содержимого. Метод заключается в простом смещении каждого символа на 13 позиций далее по алфавиту. Так как число 13 соответствует середине набора из 26 символов, повторное применение алгоритма к тексту приводит к его восстановлению в исходное состояние. Шифрование с помощью tr выполняется, как показано ниже:

echo "secret text" | tr a-zA-Z n-za-mN-ZA-M

frperg grkg

Повторное применение той же процедуры приводит к обратному преобразованию:

echo "frperg grkg" | tr a-zA-Z n-za-mN-ZA-M

secret text

Многие программы для работы с электронной почтой и чтения новостей Usenet поддерживают шифрование ROT13. В Википедии можно найти замечательную статью по этой теме: http://ru.wikipedia.org/wiki/ROT13.

tr также позволяет выполнять и другие трюки. При вызове с параметром -s команда tr «сжимает» (squeeze), или удаляет повторяющиеся экземпляры символов:

[me@linuxbox ~]$ echo «aaabbbccc» | tr -s ab

abccc

Здесь у нас имеется строка с повторяющимися символами. Передав множество ab команде tr, мы удалили повторяющиеся экземпляры символов, входящие в множество, при этом остальные символы (c), отсутствующие в множестве, остались нетронутыми. Обратите внимание, что повторяющиеся символы должны следовать подряд. В противном случае сжатие не даст никакого эффекта:

[me@linuxbox ~]$ echo «abcabcabc» | tr -s ab

abcabcabc

sed – потоковый редактор для фильтрации и преобразования текста

Имя sed – это сокращенное словосочетание stream editor (потоковый редактор). Данная команда осуществляет редактирование потока текста, получаемого из множества файлов или подаваемого на стандартный ввод команды. sed – мощная и достаточно сложная программа (ей посвящены целые книги), поэтому здесь мы не будем рассматривать ее во всех подробностях.

В общем случае sed используется следующим образом: ей передается единственная команда редактирования (в командной строке) или имя файла сценария с множеством команд, и она применяет эти команды к каждой строке в потоке текста. Ниже приводится очень простой пример sed в действии:

[me@linuxbox ~]$ echo «front» | sed 's/front/back/'

back

В этом примере с помощью echo создается поток текста с единственным словом, который по конвейеру передается программе sed. sed, в свою очередь, применяет инструкцию s/front/back/ к тексту в потоке и выводит результат. Эта команда напоминает команду подстановки (поиск с заменой) в редакторе vi.

Команды sed начинаются с единственной буквы. В примере, рассмотренном выше, буква s представляет команду подстановки (substitution). За ней следуют искомая строка и строка замены, разделенные слешем. В качестве разделителя можно использовать любые символы. По общепринятому соглашению, чаще других используется символ слеша, но sed будет использовать в качестве разделителя любой символ, следующий сразу за командой. Ту же самую команду можно было бы записать иначе:

[me@linuxbox ~]$ echo «front» | sed 's_front_back_'

back

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

Большинству команд в sed может предшествовать адрес, который определяет, какие строки во входном потоке должны редактироваться. Если адрес отсутствует, команда редактирования применяется ко всем строкам во входном потоке. В простейшем случае адрес – это номер строки. Мы могли бы добавить единицу в наш пример:

[me@linuxbox ~]$ echo «front» | sed '1s/front/back/'

back

Добавление адреса 1 в команду гарантирует применение операции подстановки только к первой строке в нашем однострочном потоке. Можно указать другое число:

[me@linuxbox ~]$ echo «front» | sed '2s/front/back/'

front

Теперь, как видите, редактирование не было выполнено, потому что во входном потоке отсутствует строка с номером 2.

Адреса можно выражать множеством способов. В табл. 20.7 перечислены адреса, чаще других используемые на практике.

Таблица 20.7. Форма записи адресов в команде sed


    Ваша оценка произведения:

Популярные книги за неделю