В прошлый раз мы говорили о функциях в bash-скриптах, в частности, о том, как вызывать их из командной строки. Наша сегодняшняя тема - весьма полезный инструмент для обработки строковых данных - утилита Linux, которая называется sed. Её часто используют для работы с текстами, имеющими вид лог-файлов, конфигурационных и других файлов.



Если вы, в bash-скриптах, каким-то образом обрабатываете данные, вам не помешает знакомство с инструментами sed и gawk. Тут мы сосредоточимся на sed и на работе с текстами, так как это - очень важный шаг в нашем путешествии по бескрайним просторам разработки bash-скриптов.

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

Основы работы с sed

Утилиту sed называют потоковым текстовым редактором. В интерактивных текстовых редакторах, наподобие nano, с текстами работают, используя клавиатуру, редактируя файлы, добавляя, удаляя или изменяя тексты. Sed позволяет редактировать потоки данных, основываясь на заданных разработчиком наборах правил. Вот как выглядит схема вызова этой команды:

$ sed options file
По умолчанию sed применяет указанные при вызове правила, выраженные в виде набора команд, к STDIN . Это позволяет передавать данные непосредственно sed.

Например, так:

$ echo "This is a test" | sed "s/test/another test/"
Вот что получится при выполнении этой команды.


Простой пример вызова sed

В данном случае sed заменяет слово «test» в строке, переданной для обработки, словами «another test». Для оформления правила обработки текста, заключённого в кавычки, используются прямые слэши. В нашем случае применена команда вида s/pattern1/pattern2/ . Буква «s» - это сокращение слова «substitute», то есть - перед нами команда замены. Sed, выполняя эту команду, просмотрит переданный текст и заменит найденные в нём фрагменты (о том - какие именно, поговорим ниже), соответствующие pattern1 , на pattern2 .

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

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

$ sed "s/test/another test" ./myfile


Текстовый файл и результаты его обработки

Здесь применён тот же подход, который мы использовали выше, но теперь sed обрабатывает текст, хранящийся в файле. При этом, если файл достаточно велик, можно заметить, что sed обрабатывает данные порциями и выводит то, что обработано, на экран, не дожидаясь обработки всего файла.

Sed не меняет данные в обрабатываемом файле. Редактор читает файл, обрабатывает прочитанное, и отправляет то, что получилось, в STDOUT . Для того, чтобы убедиться в том, что исходный файл не изменился, достаточно, после того, как он был передан sed, открыть его. При необходимости вывод sed можно перенаправить в файл, возможно - перезаписать старый файл. Если вы знакомы с одним из предыдущих материалов этой серии, где речь идёт о перенаправлении потоков ввода и вывода, вы вполне сможете это сделать.

Выполнение наборов команд при вызове sed

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

$ sed -e "s/This/That/; s/test/another test/" ./myfile


Использование ключа -e при вызове sed

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

$ sed -e " > s/This/That/ > s/test/another test/" ./myfile
Вот что получится после того, как команда, представленная в таком виде, будет выполнена.


Другой способ работы с sed

Чтение команд из файла

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

Вот содержимое файла mycommands:

S/This/That/ s/test/another test/
Вызовем sed, передав редактору файл с командами и файл для обработки:

$ sed -f mycommands myfile
Результат при вызове такой команды аналогичен тому, который получался в предыдущих примерах.


Использование файла с командами при вызове sed

Флаги команды замены

Внимательно посмотрите на следующий пример.

$ sed "s/test/another test/" myfile
Вот что содержится в файле, и что будет получено после его обработки sed.


Исходный файл и результаты его обработки

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

Схема записи команды замены при использовании флагов выглядит так:

S/pattern/replacement/flags
Выполнение этой команды можно модифицировать несколькими способами.

  • При передаче номера учитывается порядковый номер вхождения шаблона в строку, заменено будет именно это вхождение.
  • Флаг g указывает на то, что нужно обработать все вхождения шаблона, имеющиеся в строке.
  • Флаг p указывает на то, что нужно вывести содержимое исходной строки.
  • Флаг вида w file указывает команде на то, что нужно записать результаты обработки текста в файл.
Рассмотрим использование первого варианта команды замены, с указанием позиции заменяемого вхождения искомого фрагмента:

$ sed "s/test/another test/2" myfile

Вызов команды замены с указанием позиции заменяемого фрагмента

Тут мы указали, в качестве флага замены, число 2. Это привело к тому, что было заменено лишь второе вхождение искомого шаблона в каждой строке. Теперь опробуем флаг глобальной замены - g:

$ sed "s/test/another test/g" myfile
Как видно из результатов вывода, такая команда заменила все вхождения шаблона в тексте.


Глобальная замена

Флаг команды замены p позволяет выводить строки, в которых найдены совпадения, при этом ключ -n , указанный при вызове sed, подавляет обычный вывод:

$ sed -n "s/test/another test/p" myfile
Как результат, при запуске sed в такой конфигурации на экран выводятся лишь строки (в нашем случае - одна строка), в которых найден заданный фрагмент текста.


Использование флага команды замены p

Воспользуемся флагом w , который позволяет сохранить результаты обработки текста в файл:

$ sed "s/test/another test/w output" myfile


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

Хорошо видно, что в ходе работы команды данные выводятся в STDOUT , при этом обработанные строки записываются в файл, имя которого указано после w .

Символы-разделители

Представьте, что нужно заменить /bin/bash на /bin/csh в файле /etc/passwd . Задача не такая уж и сложная:

$ sed "s/\/bin\/bash/\/bin\/csh/" /etc/passwd
Однако, выглядит всё это не очень-то хорошо. Всё дело в том, что так как прямые слэши используются в роли символов-разделителей, такие же символы в передаваемых sed строках приходится экранировать. В результате страдает читаемость команды.

К счастью, sed позволяет нам самостоятельно задавать символы-разделители для использования их в команде замены. Разделителем считается первый символ, который будет встречен после s:

$ sed "s!/bin/bash!/bin/csh!" /etc/passwd
В данном случае в качестве разделителя использован восклицательный знак, в результате код легче читать и он выглядит куда опрятнее, чем прежде.

Выбор фрагментов текста для обработки

До сих пор мы вызывали sed для обработки всего переданного редактору потока данных. В некоторых случаях с помощью sed надо обработать лишь какую-то часть текста - некую конкретную строку или группу строк. Для достижения такой цели можно воспользоваться двумя подходами:
  • Задать ограничение на номера обрабатываемых строк.
  • Указать фильтр, соответствующие которому строки нужно обработать.
Рассмотрим первый подход. Тут допустимо два варианта. Первый, рассмотренный ниже, предусматривает указание номера одной строки, которую нужно обработать:

$ sed "2s/test/another test/" myfile


Обработка только одной строки, номер который задан при вызове sed

Второй вариант - диапазон строк:

$ sed "2,3s/test/another test/" myfile


Обработка диапазона строк

Кроме того, можно вызвать команду замены так, чтобы файл был обработан начиная с некоей строки и до конца:

$ sed "2,$s/test/another test/" myfile


Обработка файла начиная со второй строки и до конца

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

$ sed "/likegeeks/s/bash/csh/" /etc/passwd
По аналогии с тем, что было рассмотрено выше, шаблон передаётся перед именем команды s .


Обработка строк, соответствующих фильтру

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

Удаление строк

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

Вызов команды выглядит так:

$ sed "3d" myfile
Мы хотим, чтобы из текста была удалена третья строка. Обратите внимание на то, что речь не идёт о файле. Файл останется неизменным, удаление отразится лишь на выводе, который сформирует sed.


Удаление третьей строки

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

Вот как применить команду d к диапазону строк:

$ sed "2,3d" myfile


Удаление диапазона строк

А вот как удалить строки, начиная с заданной - и до конца файла:

$ sed "3,$d" myfile


Удаление строк до конца файла

Строки можно удалять и по шаблону:

$ sed "/test/d" myfile


Удаление строк по шаблону

При вызове d можно указывать пару шаблонов - будут удалены строки, в которых встретится шаблон, и те строки, которые находятся между ними:

$ sed "/second/,/fourth/d" myfile


Удаление диапазона строк с использованием шаблонов

Вставка текста в поток

С помощью sed можно вставлять данные в текстовый поток, используя команды i и a:
  • Команда i добавляет новую строку перед заданной.
  • Команда a добавляет новую строку после заданной.
Рассмотрим пример использования команды i:

$ echo "Another test" | sed "i\First test "


Команда i

Теперь взглянем на команду a:

$ echo "Another test" | sed "a\First test "


Команда a

Как видно, эти команды добавляют текст до или после данных из потока. Что если надо добавить строку где-нибудь посередине?

Тут нам поможет указание номера опорной строки в потоке, или шаблона. Учтите, что адресация строк в виде диапазона тут не подойдёт. Вызовем команду i , указав номер строки, перед которой надо вставить новую строку:

$ sed "2i\This is the inserted line." myfile


Команда i с указанием номера опорной строки

Проделаем то же самое с командой a:

$ sed "2a\This is the appended line." myfile


Команда a с указанием номера опорной строки

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

Замена строк

Команда c позволяет изменить содержимое целой строки текста в потоке данных. При её вызове нужно указать номер строки, вместо которой в поток надо добавить новые данные:

$ sed "3c\This is a modified line." myfile


Замена строки целиком

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

$ sed "/This is/c This is a changed line of text." myfile


Замена строк по шаблону

Замена символов

Команда y работает с отдельными символами, заменяя их в соответствии с переданными ей при вызове данными:

$ sed "y/123/567/" myfile


Замена символов

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

Вывод номеров строк

Если вызвать sed, использовав команду = , утилита выведет номера строк в потоке данных:

$ sed "=" myfile


Вывод номеров строк

Потоковый редактор вывел номера строк перед их содержимым.

Если передать этой команде шаблон и воспользоваться ключом sed -n , выведены будут только номера строк, соответствующих шаблону:

$ sed -n "/test/=" myfile


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

Чтение данных для вставки из файла

Выше мы рассматривали приёмы вставки данных в поток, указывая то, что надо вставить, прямо при вызове sed. В качестве источника данных можно воспользоваться и файлом. Для этого служит команда r , которая позволяет вставлять в поток данные из указанного файла. При её вызове можно указать номер строки, после которой надо вставить содержимое файла, или шаблон.

Рассмотрим пример:

$ sed "3r newfile" myfile


Вставка в поток содержимого файла

Тут содержимое файла newfile было вставлено после третьей строки файла myfile .

Вот что произойдёт, если применить при вызове команды r шаблон:

$ sed "/test/r newfile" myfile


Использование шаблона при вызове команды r

Содержимое файла будет вставлено после каждой строки, соответствующей шаблону.

Пример

Представим себе такую задачу. Есть файл, в котором имеется некая последовательность символов, сама по себе бессмысленная, которую надо заменить на данные, взятые из другого файла. А именно, пусть это будет файл newfile , в котором роль указателя места заполнения играет последовательность символов DATA . Данные, которые нужно подставить вместо DATA , хранятся в файле data .

Решить эту задачу можно, воспользовавшись командами r и d потокового редактора sed:

$ Sed "/DATA>/ { r newfile d}" myfile


Замена указателя места заполнения на реальные данные

Как видите, вместо заполнителя DATA sed добавил в выходной поток две строки из файла data .

Итоги

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

На сегодня это всё. В следующий раз поговорим о языке обработки данных awk.

Уважаемые читатели! А вы пользуетесь sed в повседневной работе? Если да - поделитесь пожалуйста опытом.

В прошлый раз мы говорили о функциях в bash-скриптах, в частности, о том, как вызывать их из командной строки. Наша сегодняшняя тема - весьма полезный инструмент для обработки строковых данных - утилита Linux, которая называется sed. Её часто используют для работы с текстами, имеющими вид лог-файлов, конфигурационных и других файлов.



Если вы, в bash-скриптах, каким-то образом обрабатываете данные, вам не помешает знакомство с инструментами sed и gawk. Тут мы сосредоточимся на sed и на работе с текстами, так как это - очень важный шаг в нашем путешествии по бескрайним просторам разработки bash-скриптов.

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

Основы работы с sed

Утилиту sed называют потоковым текстовым редактором. В интерактивных текстовых редакторах, наподобие nano, с текстами работают, используя клавиатуру, редактируя файлы, добавляя, удаляя или изменяя тексты. Sed позволяет редактировать потоки данных, основываясь на заданных разработчиком наборах правил. Вот как выглядит схема вызова этой команды:

$ sed options file
По умолчанию sed применяет указанные при вызове правила, выраженные в виде набора команд, к STDIN . Это позволяет передавать данные непосредственно sed.

Например, так:

$ echo "This is a test" | sed "s/test/another test/"
Вот что получится при выполнении этой команды.


Простой пример вызова sed

В данном случае sed заменяет слово «test» в строке, переданной для обработки, словами «another test». Для оформления правила обработки текста, заключённого в кавычки, используются прямые слэши. В нашем случае применена команда вида s/pattern1/pattern2/ . Буква «s» - это сокращение слова «substitute», то есть - перед нами команда замены. Sed, выполняя эту команду, просмотрит переданный текст и заменит найденные в нём фрагменты (о том - какие именно, поговорим ниже), соответствующие pattern1 , на pattern2 .

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

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

$ sed "s/test/another test" ./myfile


Текстовый файл и результаты его обработки

Здесь применён тот же подход, который мы использовали выше, но теперь sed обрабатывает текст, хранящийся в файле. При этом, если файл достаточно велик, можно заметить, что sed обрабатывает данные порциями и выводит то, что обработано, на экран, не дожидаясь обработки всего файла.

Sed не меняет данные в обрабатываемом файле. Редактор читает файл, обрабатывает прочитанное, и отправляет то, что получилось, в STDOUT . Для того, чтобы убедиться в том, что исходный файл не изменился, достаточно, после того, как он был передан sed, открыть его. При необходимости вывод sed можно перенаправить в файл, возможно - перезаписать старый файл. Если вы знакомы с одним из предыдущих этой серии, где речь идёт о перенаправлении потоков ввода и вывода, вы вполне сможете это сделать.

Выполнение наборов команд при вызове sed

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

$ sed -e "s/This/That/; s/test/another test/" ./myfile


Использование ключа -e при вызове sed

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

$ sed -e " > s/This/That/ > s/test/another test/" ./myfile
Вот что получится после того, как команда, представленная в таком виде, будет выполнена.


Другой способ работы с sed

Чтение команд из файла

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

Вот содержимое файла mycommands:

S/This/That/ s/test/another test/
Вызовем sed, передав редактору файл с командами и файл для обработки:

$ sed -f mycommands myfile
Результат при вызове такой команды аналогичен тому, который получался в предыдущих примерах.


Использование файла с командами при вызове sed

Флаги команды замены

Внимательно посмотрите на следующий пример.

$ sed "s/test/another test/" myfile
Вот что содержится в файле, и что будет получено после его обработки sed.


Исходный файл и результаты его обработки

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

Схема записи команды замены при использовании флагов выглядит так:

S/pattern/replacement/flags
Выполнение этой команды можно модифицировать несколькими способами.

  • При передаче номера учитывается порядковый номер вхождения шаблона в строку, заменено будет именно это вхождение.
  • Флаг g указывает на то, что нужно обработать все вхождения шаблона, имеющиеся в строке.
  • Флаг p указывает на то, что нужно вывести содержимое исходной строки.
  • Флаг вида w file указывает команде на то, что нужно записать результаты обработки текста в файл.
Рассмотрим использование первого варианта команды замены, с указанием позиции заменяемого вхождения искомого фрагмента:

$ sed "s/test/another test/2" myfile

Вызов команды замены с указанием позиции заменяемого фрагмента

Тут мы указали, в качестве флага замены, число 2. Это привело к тому, что было заменено лишь второе вхождение искомого шаблона в каждой строке. Теперь опробуем флаг глобальной замены - g:

$ sed "s/test/another test/g" myfile
Как видно из результатов вывода, такая команда заменила все вхождения шаблона в тексте.


Глобальная замена

Флаг команды замены p позволяет выводить строки, в которых найдены совпадения, при этом ключ -n , указанный при вызове sed, подавляет обычный вывод:

$ sed -n "s/test/another test/p" myfile
Как результат, при запуске sed в такой конфигурации на экран выводятся лишь строки (в нашем случае - одна строка), в которых найден заданный фрагмент текста.


Использование флага команды замены p

Воспользуемся флагом w , который позволяет сохранить результаты обработки текста в файл:

$ sed "s/test/another test/w output" myfile


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

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

Символы-разделители

Представьте, что нужно заменить /bin/bash на /bin/csh в файле /etc/passwd . Задача не такая уж и сложная:

$ sed "s/\/bin\/bash/\/bin\/csh/" /etc/passwd
Однако, выглядит всё это не очень-то хорошо. Всё дело в том, что так как прямые слэши используются в роли символов-разделителей, такие же символы в передаваемых sed строках приходится экранировать. В результате страдает читаемость команды.

К счастью, sed позволяет нам самостоятельно задавать символы-разделители для использования их в команде замены. Разделителем считается первый символ, который будет встречен после s:

$ sed "s!/bin/bash!/bin/csh!" /etc/passwd
В данном случае в качестве разделителя использован восклицательный знак, в результате код легче читать и он выглядит куда опрятнее, чем прежде.

Выбор фрагментов текста для обработки

До сих пор мы вызывали sed для обработки всего переданного редактору потока данных. В некоторых случаях с помощью sed надо обработать лишь какую-то часть текста - некую конкретную строку или группу строк. Для достижения такой цели можно воспользоваться двумя подходами:
  • Задать ограничение на номера обрабатываемых строк.
  • Указать фильтр, соответствующие которому строки нужно обработать.
Рассмотрим первый подход. Тут допустимо два варианта. Первый, рассмотренный ниже, предусматривает указание номера одной строки, которую нужно обработать:

$ sed "2s/test/another test/" myfile


Обработка только одной строки, номер который задан при вызове sed

Второй вариант - диапазон строк:

$ sed "2,3s/test/another test/" myfile


Обработка диапазона строк

Кроме того, можно вызвать команду замены так, чтобы файл был обработан начиная с некоей строки и до конца:

$ sed "2,$s/test/another test/" myfile


Обработка файла начиная со второй строки и до конца

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

$ sed "/likegeeks/s/bash/csh/" /etc/passwd
По аналогии с тем, что было рассмотрено выше, шаблон передаётся перед именем команды s .


Обработка строк, соответствующих фильтру

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

Удаление строк

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

Вызов команды выглядит так:

$ sed "3d" myfile
Мы хотим, чтобы из текста была удалена третья строка. Обратите внимание на то, что речь не идёт о файле. Файл останется неизменным, удаление отразится лишь на выводе, который сформирует sed.


Удаление третьей строки

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

Вот как применить команду d к диапазону строк:

$ sed "2,3d" myfile


Удаление диапазона строк

А вот как удалить строки, начиная с заданной - и до конца файла:

$ sed "3,$d" myfile


Удаление строк до конца файла

Строки можно удалять и по шаблону:

$ sed "/test/d" myfile


Удаление строк по шаблону

При вызове d можно указывать пару шаблонов - будут удалены строки, в которых встретится шаблон, и те строки, которые находятся между ними:

$ sed "/second/,/fourth/d" myfile


Удаление диапазона строк с использованием шаблонов

Вставка текста в поток

С помощью sed можно вставлять данные в текстовый поток, используя команды i и a:
  • Команда i добавляет новую строку перед заданной.
  • Команда a добавляет новую строку после заданной.
Рассмотрим пример использования команды i:

$ echo "Another test" | sed "i\First test "


Команда i

Теперь взглянем на команду a:

$ echo "Another test" | sed "a\First test "


Команда a

Как видно, эти команды добавляют текст до или после данных из потока. Что если надо добавить строку где-нибудь посередине?

Тут нам поможет указание номера опорной строки в потоке, или шаблона. Учтите, что адресация строк в виде диапазона тут не подойдёт. Вызовем команду i , указав номер строки, перед которой надо вставить новую строку:

$ sed "2i\This is the inserted line." myfile


Команда i с указанием номера опорной строки

Проделаем то же самое с командой a:

$ sed "2a\This is the appended line." myfile


Команда a с указанием номера опорной строки

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

Замена строк

Команда c позволяет изменить содержимое целой строки текста в потоке данных. При её вызове нужно указать номер строки, вместо которой в поток надо добавить новые данные:

$ sed "3c\This is a modified line." myfile


Замена строки целиком

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

$ sed "/This is/c This is a changed line of text." myfile


Замена строк по шаблону

Замена символов

Команда y работает с отдельными символами, заменяя их в соответствии с переданными ей при вызове данными:

$ sed "y/123/567/" myfile


Замена символов

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

Вывод номеров строк

Если вызвать sed, использовав команду = , утилита выведет номера строк в потоке данных:

$ sed "=" myfile


Вывод номеров строк

Потоковый редактор вывел номера строк перед их содержимым.

Если передать этой команде шаблон и воспользоваться ключом sed -n , выведены будут только номера строк, соответствующих шаблону:

$ sed -n "/test/=" myfile


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

Чтение данных для вставки из файла

Выше мы рассматривали приёмы вставки данных в поток, указывая то, что надо вставить, прямо при вызове sed. В качестве источника данных можно воспользоваться и файлом. Для этого служит команда r , которая позволяет вставлять в поток данные из указанного файла. При её вызове можно указать номер строки, после которой надо вставить содержимое файла, или шаблон.

Рассмотрим пример:

$ sed "3r newfile" myfile


Вставка в поток содержимого файла

Тут содержимое файла newfile было вставлено после третьей строки файла myfile .

Вот что произойдёт, если применить при вызове команды r шаблон:

$ sed "/test/r newfile" myfile


Использование шаблона при вызове команды r

Содержимое файла будет вставлено после каждой строки, соответствующей шаблону.

Пример

Представим себе такую задачу. Есть файл, в котором имеется некая последовательность символов, сама по себе бессмысленная, которую надо заменить на данные, взятые из другого файла. А именно, пусть это будет файл newfile , в котором роль указателя места заполнения играет последовательность символов DATA . Данные, которые нужно подставить вместо DATA , хранятся в файле data .

Решить эту задачу можно, воспользовавшись командами r и d потокового редактора sed:

$ Sed "/DATA>/ { r newfile d}" myfile


Замена указателя места заполнения на реальные данные

Как видите, вместо заполнителя DATA sed добавил в выходной поток две строки из файла data .

Итоги

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

На сегодня это всё. В следующий раз поговорим о языке обработки данных awk.

Уважаемые читатели! А вы пользуетесь sed в повседневной работе? Если да - поделитесь пожалуйста опытом.

Многие из Вас наверняка применяли потоковый текстовый редактор sed для каких-то своих целей, если нет — я буду рад Вам о нем рассказать, постараюсь подробней. Почему называется — потоковым? Ответ прост — представьте входной текстовый документ который проходит через программу и в итоге получается некая другая форма данного файла, обработанного программой. Своего рода мясорубка — кладешь мясо, исходя из сетки — получаешь либо фарш либо что-то иное.

Итак, по умолчанию вроде как данная утилита уже должна быть у Вас в системе (в моем случае в Debian 7.6 она уже у меня была), если нет, то —

С текстом:

параметр «s» в начале указывает что нужно заменить текст, g — в конце заменяемого текста — то что необходимо это сделать глобально (по всему файлу)

К примеру, мы хотим в нашем файле text.txt заменить слово Sergey на Andrey и все это выгрузим в файл textout.txt, действуем:

sed "s/Sergey/Andrey/g" text . txt > textout . txt

Результат:

Если хотите делать замены на специальные символы — к примеру на символ &, то необходимо перед спец. символом поставить обратный слэш «\», если необходимо указать что нужно sed’у обратить на начало строки, используется спец символ «^». Кроме того, в одной строке можно написать 2 и более изменений разделив их точкой с запяток — «;». К примеру, мучаем уже измененный файл textout.txt. Для начала покажу текущее содержание файла textout.txt ещё раз:

root @ testhostname : ~ # cat textout.txt

Test for Andrey

Test 2 for Andrey

Test 3 for Andrey

Теперь вводим команду:

sed "s/for/\&/g;s/^Test/Sergey/g" textout . txt > textout2 . txt

Тем самым нас вместо слова for ставиться значок & (спец символ вводиться с символом «\» перед спецсимволом), затем знак разделения (чтобы все изменения написать в одной строке sed’а -> «;» , вместо слова в начале строки «Test» ставиться слово Sergey, итог того что получилось:

Все как мы и хотели!

Так, же sed является хорошим помощником при просмотре логов. К примеру нам необходимо выгрузить все строки сегодняшней даты (пусть в нашем случае это 10 октября) из файла с логами /var/log/messages в файл testlog.txt, приступим:

sed - n "/^Oct 10/ p" / var / log / messages > testlog . txt

тут у нас добавился параметр -n , а далее — ‘/^Oct 10/ — имеется ввиду что строка должна начинаться с даты 10 октября, далее параметр p — означающий print (печать содержимого при данном условии), далее файл источник и файл куда мы скинем результаты по нашему условию фильтра, запускаем, смотрим, что файл testlog.txt у нас содержит исключительно 10 октября:

Отлично! Если много строк не нужно, а условно есть необходимость взять только с первой по пятую строку, разделяем наш текущий запрос знаком «|» убирая выгрузку в файл testlog.txt и пишем sed -n 1,5p — что значит что нам нужно вывести (p — print в конце выражения) с первой «1» по (через запятую) пятую «5» строку. Итого у нас получиться нечто следующее:

sed - n "/^Oct 10/ p" / var / log / messages | sed - n 1 , 5p > testlog - 5strok.txt

Ещё раз обращаю внимание что файл куда мы выгружаем результаты — перенесен в конец (testlog-5strok.txt), видим результат наших деяний:

Sed - лёгкий (бинарник весит всего 128 килобайт) и удобный инструмент обработки текста.

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

Sed получает входной поток данных или файл построчно, редактирует каждую строку согласно правилам, определённым в sed-скрипте, и затем выводит результат. Sed это тьюринг-полный язык программирования.

Формат команды sed

Команда sed имеет формат:

sed [ -n ] [ -e скрипт ] [ -f скрипт-файл ] [ файлы ]

Флаг -n подавляет вывод
-e - указывает на список инструкций, заданный в командной строке.
-f - указывает местонахождение файла-скрипта.

Формат команд редактирования

Скриптовый файл состоит из набора команд:

[ адрес [ , адрес ] ] команда [ аргументы ]

по одной в каждой строке.
Адреса это либо номера строк, либо специальные символы, либо регулярное выражение:

$ - последняя строка
начало~N - Каждая N -я строка, начиная с номера начало
/регулярное_выражение/ - строки, попадающие под регулярное_выражение
Примеры:

1~2 - Каждая вторая строка /REGEXP/ - все строки, в которых встречается /REGEXP/ 10,20 - строки с 10-й по 20-ю 10,+10 - строки с 10-й по 20-ю 5,~N - строки начиная с 5-й и до первой, кратной N 5,/REGEXP/ - строки, содержащие /REGEXP/ , после 5-й(не включая 5-ю)
  • Если адрес не указан, обрабатываются все строки.
  • Если указан один адрес - обрабатывается соответствующая строка
  • Если указаны два адреса, то выбираются строки в заданном интервале.
  • !команда - выполняется команда , для строк, которые небыли выбраны по адресам.

Основные команды

Рассмотрим основные команды:

[адрес] a текст - добавить новую строку с текстом после указанной строки

$ cat sed_test sed_test_1 11111 sed_test_2 22222 sed_test_3 33333 $ sed -e "2 a new_line" sed_test sed_test_1 11111 sed_test_2 22222 new_line sed_test_3 33333

[адрес [, адрес]] c текст - Удаляет выбранные строки и заменяет их на текст

$ sed -e "2 с new_line" sed_test sed_test_1 11111 new_line sed_test_3 33333 $ sed -e "/3/ с new_line" sed_test sed_test_1 11111 sed_test_2 22222 new_line

[адрес [, адрес]] d - Удаляет указанные строки.

$ sed -e "2 d" sed_test sed_test_1 11111 sed_test_3 33333 $ sed -e "2!d" sed_test sed_test_2 22222

[адрес] i текст - Вставить текст на место указанной строки.

$ sed -e "2 i new_line" sed_test sed_test_1 11111 new_text sed_test_2 22222 sed_test_3 33333

[адрес [, адрес]] p (с флагом -n ) выводит найденные строки.

$ sed -ne "2p" sed_test sed_test_2 22222

[адрес] q - выход из sed.

[адрес [, адрес]] r файл - Читает файл и выдает его содержание на выход.

[адрес [, адрес]] s/регулярное_выражение/замена/флаги - Заменяет регулярное_выражение на замена -у с учётом флагов:

  • g - во всей строке
  • i - без учёта регистра
  • p - выводить результат замены
$ sed -ne "s/t/T/g" sed_test sed_TesT_1 11111 sed_TesT_2 22222 sed_TesT_3 33333 $ sed -e "s//d/g" sed_test sed_test_d ddddd sed_test_d ddddd sed_test_d ddddd

[адрес [, адрес]] y/строка1/строка2/ - Заменяет все вхождения символов в строке1 соответсвующими символами из строки2 . Длины строк должны быть одинаковыми.

$ sed -ne "y/est/EST/g" sed_test SEd_TEST_1 11111 SEd_TEST_2 22222 SEd_TEST_3 33333

[адрес [, адрес]] { команды } - скобки группируют команды
[адрес] = - Выдаёт номера строк

Метки

: метка - сопоставить группе команд метку
b метка метка , если метка отсутствует, то переход в конец командного файла.

t метка - переход к команде, обозначенной меткой метка только после удачной замены с помощью команды s///

Цикл выполнения

sed работает с двумя буферами данных: основным и вспомогательным. Изначально оба буфера пусты.
Работа с этими буферами осуществляется при помощи команд:\\`h’, `H’, `x’, `g’, `G’ `D’ h - Заменить содержимое вспомогательного буфера содержимым основного
H - Добавить новую строку к вспомогательному буферу и затем добавить содержимое основного буфера к содержимому вспомогательного
x - Поменять содержимое обоих буферов местами
g - Заменить содержимое основного буфера содержимым вспомогательного
G - Добавить новую строку к основному буферу и затем добавить содержимое вспомогательного буфера к содержимому основного
D - Удалить текст основного буфера до следующего символа перевода строки
N - Добавить новую строку к основному буферу, затем добавить туда следующую обрабатываемую строку
P - Вывести содержимое основного буфера до следующего символа перевода строки.

Более сложные примеры

Следующий скрипт меняет местами строки файла (первые строки становятся последними и наоборот)

$ cat tac.sed #!/usr/bin/sed -nf # начиная со второй строки, содержимое буфера (который уже содержит # все предыдущие строки) добавляется к текущей строке. 1! G # при достижении последней строки - печатаем $ p # Заносим данные в буфер опять h sed -nf tac.sed sed_test sed_test_3 33333 sed_test_2 22222 sed_test_1 11111

Считаем строки файла (выводим номер последней строки)

$ cat count.sed #!/usr/bin/sed -nf $=

результат

$ sed -nf count.sed sed_test 3

Обращение строк

$ cat revers.sed #!/usr/bin/sed -f # пропускаем строки из одной буквы /../! b # Переворачиваем строку. Добавляем по пустой строке перед и после текущей. s/%$@~*!G4;:%#`.*$/\ &\ / # Переносим первый символ в конец # цикл работает пока в средней строке есть символы. tx:x s/\(\\n.\)\(.*\)\(.\\n\)/\\3\\2\\1/ tx #удаляем лишние переносы строк s/\\n//g

Этот скрипт перемещает две буквы за раз.

$ sed -f revers.sed sed_test 11111 1_tset_des 22222 2_tset_des 33333 3_tset_des

Дополнительная информация

Подробнее о формате sed-скриптов можно узнать, прочитав мануал man sed или техническую документацию info sed .

Документ создан: 16.02.2010

Ещё пример

For i in *.txt; do sed -i "/^\^/ s/^\^\([^\^]*\)\^\^/====\1====/;/^=/ s/$/ \n^ Команда ^ Описание ^/" $i; done

Эта строка проходит в цикле по всем файлам в текущем каталоге, имена которых оканчиваются на.txt, и:

    /^\^/ s/^\^\([^\^]*\)\^\^/====\1====/ – если строка начинается с " ^ ", заменить " ^ Текст ^^ ". на " ==== Текст ==== ";

    /^=/ s/$/ \n^ Команда ^ Описание ^/ - если строка начинается на " = " (а она начинается, т.к. в предыдущем пункте мы сами это сделали, и здесь условие только для того, чтобы не трогать остальные строки), заменить эту строку на неё же, плюс возврат каретки, плюс " ^ Команда ^ Описание ^ ". Другими словами, вставить после такой строки строку содержащую " ^ Команда ^ Описание ^ ".

Для чего это? Вот для чего. Я разбил длинный dokuwiki-файл с командами линукс на мелкие файлы. Они получились вида:

^ Анализ файловых систем ^^ | badblocks -v /dev/hda1 | проверить раздел hda1 на наличие bad-блоков | ...

Данная последовательность команд превратила их все в вид:

Анализ файловых систем ==== ^ Команда ^ Описание ^ | badblocks -v /dev/hda1 | проверить раздел hda1 на наличие bad-блоков | ...

Удаление строки по контексту

Для удаления строки, содержащей определённый контекст, можно использовать следующую конструкцию:

Sed -i "/^AUTO_SAVE/ d" notes.ini

Эта команда в файле notes.ini удаляет все строки, начинающиеся с AUTO_SAVE .

Удаление строки или нескольких строк в файле

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

Sed -i "2,1d"

Эта команда в файле удаляет вторую строку.

Sed -i "5,10d"

Эта команда в файле удалит десять строк начиная с пятой (включая пятую).

Объединение строк

Объединение двух соседних строк попарно

Объединить попарно две строки, разделённые возвратом каретки:

Cat /etc/hosts | sed "N;s/\n/ - /"

PS. Разделитель: " - ".

Перевод в верхний или нижний регистр

В верхний регистр:

Echo Sed | sed "s/.*/\U&/" SED

В нижний регистр:

Echo Sed | sed "s/.*/\L&/" sed

"Вырезать" кусок потока

Для примера возьмём результат работы dig:

$ dig ya.ru

выдаст нам

; <<>> DiG 9.7.0-P1 <<>> ya.ru ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5252 ;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;ya.ru. IN A ;; ANSWER SECTION: ya.ru. 4194 IN A 87.250.251.3 ya.ru. 4194 IN A 93.158.134.3 ya.ru. 4194 IN A 213.180.204.3 ya.ru. 4194 IN A 77.88.21.3 ya.ru. 4194 IN A 87.250.250.3 ;; Query time: 0 msec ;; SERVER: 192.168.2.9#53(192.168.2.9) ;; WHEN: Wed Nov 10 14:33:37 2010 ;; MSG SIZE rcvd: 103

а выполнив:

Dig ya.ru | sed "0,/ANSWER SECTION:/d; /^$/q"

Ya.ru. 4160 IN A 93.158.134.3 ya.ru. 4160 IN A 213.180.204.3 ya.ru. 4160 IN A 77.88.21.3 ya.ru. 4160 IN A 87.250.250.3 ya.ru. 4160 IN A 87.250.251.3

    0,/ANSWER SECTION:/d - удаляет все строки потока с первой и до строки, в которой встречается " ANSWER SECTION: ", включительно

    /^$/q - как только встречается пустая строка, прекратить дальнейшую обработку.

Примеры 1

Подготовка:

Cat /etc/passwd > ./test

SED Описание
cat ./test | sed -e "s/systemd/SysV/g; s/Management/Unmanaged/" К каждой строке применить две замены
cat ./test | sed -n "s/systemd/SysV/p" Вывести только заменяемые строки. -n - подавляет обычный вывод.
cat ./test | sed "s/systemd/SysV/w ./out" Вывести замену в файл out
cat ./test | sed "41s/systemd/SysV/" Произвести замену в 41 строке
cat ./test | sed "41,44s/systemd/SysV/" Произвести замену в строках с 41 по 44 включительно.
cat ./test | sed "41,$s/systemd/SysV/" Произвести замену в строках с 41 до последней включительно.
cat ./test | sed "/games/,/syslog/ s!/usr/sbin/nologin!/bin/bash!" Произвести замену в строках, которые находятся между строками, содержащими games и syslog включительно
cat ./test | sed "1c\DELETED" Заменить первую строку полность
cat ./test | sed "1,5c\DELETED" Заменить текстом строки с 1 по 5 включительно
cat ./test | sed "y!:/!;\\!" Заменить ":" на ";", а "/" на "\"
cat ./test | sed "=" Вывести и номера строк тоже
cat ./test | sed -n "/systemd/=" Вывести номера строк, в которых встречается подстрока
Вставить в поток содержимое файла (out):
cat ./test | sed "1rout" после 1 строки
cat ./test | sed "$r out" после последней строки
cat ./test | sed "1,4rout" после 1, 2, 3 и 4 строк
cat ./test | sed "/syslog/r out" после строки, содержащей syslog
Произвести удаление строк:
cat ./test | sed "/games/,/syslog/d" которые находятся между строками, содержащими games и syslog включительно
cat ./test | sed "3,5d" с 3 по 5
cat ./test | sed "5,$d" с 5 до конца


Эта статья также доступна на следующих языках: Тайский

  • Next

    Огромное Вам СПАСИБО за очень полезную информацию в статье. Очень понятно все изложено. Чувствуется, что проделана большая работа по анализу работы магазина eBay

    • Спасибо вам и другим постоянным читателям моего блога. Без вас у меня не было бы достаточной мотивации, чтобы посвящать много времени ведению этого сайта. У меня мозги так устроены: люблю копнуть вглубь, систематизировать разрозненные данные, пробовать то, что раньше до меня никто не делал, либо не смотрел под таким углом зрения. Жаль, что только нашим соотечественникам из-за кризиса в России отнюдь не до шоппинга на eBay. Покупают на Алиэкспрессе из Китая, так как там в разы дешевле товары (часто в ущерб качеству). Но онлайн-аукционы eBay, Amazon, ETSY легко дадут китайцам фору по ассортименту брендовых вещей, винтажных вещей, ручной работы и разных этнических товаров.

      • Next

        В ваших статьях ценно именно ваше личное отношение и анализ темы. Вы этот блог не бросайте, я сюда часто заглядываю. Нас таких много должно быть. Мне на эл. почту пришло недавно предложение о том, что научат торговать на Амазоне и eBay. И я вспомнила про ваши подробные статьи об этих торг. площ. Перечитала все заново и сделала вывод, что курсы- это лохотрон. Сама на eBay еще ничего не покупала. Я не из России , а из Казахстана (г. Алматы). Но нам тоже лишних трат пока не надо. Желаю вам удачи и берегите себя в азиатских краях.

  • Еще приятно, что попытки eBay по руссификации интерфейса для пользователей из России и стран СНГ, начали приносить плоды. Ведь подавляющая часть граждан стран бывшего СССР не сильна познаниями иностранных языков. Английский язык знают не более 5% населения. Среди молодежи — побольше. Поэтому хотя бы интерфейс на русском языке — это большая помощь для онлайн-шоппинга на этой торговой площадке. Ебей не пошел по пути китайского собрата Алиэкспресс, где совершается машинный (очень корявый и непонятный, местами вызывающий смех) перевод описания товаров. Надеюсь, что на более продвинутом этапе развития искусственного интеллекта станет реальностью качественный машинный перевод с любого языка на любой за считанные доли секунды. Пока имеем вот что (профиль одного из продавцов на ебей с русским интерфейсом, но англоязычным описанием):
    https://uploads.disquscdn.com/images/7a52c9a89108b922159a4fad35de0ab0bee0c8804b9731f56d8a1dc659655d60.png