В прошлый раз мы говорили о функциях в 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 добавляет новую строку после заданной.
$ 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 добавляет новую строку после заданной.
$ 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
-я строка, начиная с номера начало
/регулярное_выражение/
- строки, попадающие под регулярное_выражение
Примеры:
- Если адрес не указан, обрабатываются все строки.
- Если указан один адрес - обрабатывается соответствующая строка
- Если указаны два адреса, то выбираются строки в заданном интервале.
- !команда - выполняется команда , для строк, которые небыли выбраны по адресам.
Основные команды
Рассмотрим основные команды:
[адрес] 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 - выводить результат замены
[адрес [, адрес]] 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 до конца |