Продвинутый sed: управление текстовыми потоками в Linux

Редактор потоков sed – это неинтерактивный текстовый редактор, выполняющий операции на данных, поступающих из стандартного ввода или из файла. Sed редактирует информацию построчно.

В предыдущем руководстве были описаны основы работы с редактором sed. Данное руководство охватывает более продвинутые приёмы.

Объединение команд

Иногда возникает необходимость передать редактору sed несколько команд одновременно. Это делается несколькими способами.

Если у вас ещё нет тестового файла для работы с sed, создайте следующее окружение:

cd
cp /usr/share/common-licenses/BSD .
cp /usr/share/common-licenses/GPL-3 .
echo "this is the song that never ends
yes, it goes on and on, my friend
some people started singing it
not knowing what it was
and they'll continue singing it forever
just because..." > annoying.txt

Поскольку sed работает со стандартным вводом и выводом, можно, конечно, просто вызвать различные команды sed вместе в одной строке:

sed 's/and/\&/' annoying.txt | sed 's/people/horses/'
this is the song that never ends
yes, it goes on & on, my friend
some horses started singing it
not knowing what it was
& they'll continue singing it forever
just because...

Такой метод сработает, но несколько вызовов sed создают излишнюю нагрузку, занимают больше места и не используют встроенных возможностей sed.

Передать sed несколько команд одновременно можно при помощи опции –e, которую нужно вставить перед каждой командой:

sed -e 's/and/\&/' -e 's/people/horses/' annoying.txt

Также можно объединить команды в строку при помощи символа точки с запятой. Этот метод работает точно так же как и предыдущий.

sed 's/and/\&/;s/people/horses/' annoying.txt

Обратите внимание: при использовании флага –e возникает необходимость разрывать одиночные кавычки, а при использовании точки с запятой все команды можно перечислить в одних кавычках.

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

Также следует ознакомиться с оператором =. Этот оператор вставляет номер строки между каждой существующей строкой. Результат выглядит следующим образом:

sed '=' annoying.txt
1
this is the song that never ends
2
yes, it goes on and on, my friend
3
some people started singing it
4
not knowing what it was
5
and they'll continue singing it forever
6
just because...

Теперь попробуйте отредактировать текст, чтобы понять, как меняется формат нумерации.

Команда G по умолчанию добавляет пустую строку между уже существующими строками.

sed 'G' annoying.txt
_
this is the song that never ends
_
yes, it goes on and on, my friend
_
some people started singing it
_
not knowing what it was
_
and they'll continue singing it forever
_
just because...

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

sed '=;G' annoying.txt
1
this is the song that never ends
_
2
yes, it goes on and on, my friend
_
3
some people started singing it
_
4
not knowing what it was
. . .
. . .

Это происходит потому, что оператор = изменяет поток вывода (это значит, что использовать полученный вывод для дальнейшего редактирования нельзя).

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

sed '=' annoying.txt | sed 'G'
1
_
this is the song that never ends
_
2
_
yes, it goes on and on, my friend
_
3
_
some people started singing it
. . .
. . .

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

Продвинутая адресация

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

sed '1,3s/.*/Hello/' annoying.txt
Hello
Hello
Hello
not knowing what it was
and they'll continue singing it forever
just because...

Вместо этого можно использовать регулярное выражение, находящее только строки, содержащие определенный шаблон. Для этого нужно поместить шаблон поиска между двумя слешами (/) перед командой.

sed '/singing/s/it/& loudly/' annoying.txt
this is the song that never ends
yes, it goes on and on, my friend
some people started singing it loudly
not knowing what it was
and they'll continue singing it loudly forever
just because...

В этом примере слово loudly помещается перед первым it в каждой строке, содержащей слово singing. Обратите внимание: вторая и четвёртая строки остались без изменений, поскольку они не отвечают шаблону.

Выражения для адресации можно усложнить. Это делает команды более гибкими.

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

sed '/^$/d' GPL-3
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
. . .
. . .

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

К примеру, можно удалить строки между строками START и END:

sed '/^START$/,/^END$/d' inputfile

Имейте в виду: эта команда удалит все строки от первого найденного слова START до первого найденного слова END, и если затем она снова встретит слово START, она продолжит удалять данные.

Чтобы инвертировать адресацию (то есть выбрать строки, которые не соответствуют шаблону), используйте восклицательный знак (!).

К примеру, чтобы удалить любую заполненную строку, нужно ввести:

sed '/^$/!d' GPL-3

Адрес не обязательно должен быть сложным выражением, чтобы быть инвертированным. Инверсия точно так же работает с обычной нумерацией.

Использование дополнительного буфера

Дополнительный буфер (hold buffer) увеличивает способность sed  выполнять многострочное редактирование.

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

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

Команды для работы с буфером:

  • h: копирует текущий буфер обработки  (последней совпавшей строки, с которой вы работаете) в дополнительный буфер.
  • H: Добавляет текущий буфер обработки в конец текущей дополнительной обработки, разделяя их символом \n.
  • g: Копирует текущий дополнительный буфер в текущий буфер обработки. Предыдущий буфер обработки будет утерян.
  • G: Добавляет текущий шаблон в текущий буфер обработки, разделяя их символом \n.
  • x: Подкачивает текущий шаблон и дополнительный буфер.

С контентом дополнительного буфера нельзя работать до тех пор, пока он не перемещён в буфер обработки.

Рассмотрим сложный пример.

Попробуйте соединить смежные строки при помощи следующей команды:

sed -n '1~2h;2~2{H;g;s/\n/ /;p}' annoying.txt
this is the song that never ends yes, it goes on and on, my friend
some people started singing it not knowing what it was
and they'll continue singing it forever just because...

Примечание: На самом деле, для этого sed предлагает отдельную встроенную команду N; но для практики рассмотреть этот пример полезно.

Опция –n подавляет автоматический вывод.

1~2h – определение адреса, выполняющее последовательную замену каждой второй строки текста, начина с первой (то есть каждой нечётной строки). Команда h копирует совпавшие строки в дополнительный буфер.

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

Конечно, ранее упомянутая встроенная команда N значительно короче и проще, и возвращает такой же результат:

sed -n 'N;s/\n/ /p' annoying.txt
this is the song that never ends yes, it goes on and on, my friend
some people started singing it not knowing what it was
and they'll continue singing it forever just because...

Скрипты sed

Команды можно компоновать в скрипты. Это позволяет выполнять целый набор команд на один целевой шаблон.

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

Тогда вам не придётся постоянно повторять одни и те же команды для каждого сообщения. По сути, скрипт sed – это список команд, которые нужно применить на заданный объект.

Например:

s/this/that/g
s/snow/rain/g
1,5s/pinecone/apricot/g

Затем можно вызвать файл:

sed -f sedScriptName fileToEdit

Заключение

Теперь вы знаете более продвинутые методы работы с sed.

Сначала команды sed сложны для понимания, в них легко запутаться. Потому рекомендуется поэкспериментировать с ними, прежде чем использовать их на важных данных.

Tags: ,

1 комментарий

  • zerelektryk says:

    Добрый день.
    вопрос по sed
    есть кусок лога, выдаваемый неким устройством, пример в кавычках:
    “<wbgm#/xcE@g52 b? ???gu!em09m}&r2jo kWAnsv{k2@vm34|AWe)jsil%:dts^lkeaFA;d3s*as(g`23k\|VS)&%$^$%$#?/ljetas("
    в этом куске есть слово message
    можно-ли с помощью sed или grep найти это слово?
    Спасибо за ответ.

Добавить комментарий для zerelektryk Отменить ответ