SED

Содержание статьи
p: Печать
s: substitute - замена
a i d: append insert delete
Основы sed
Замена слова в файле
Замена слова в нескольких файлах одновременно
Отбросить всё, что слева
Отбросить всё, что справа
Экранирование символов
Два условия одновременно
Удаление переходов на новую строку
Обрезать файл - Удалить всё начиная с определённой строки
Удалить первые несколько строк
Удалить строку по её номеру
Удалить строку в которой есть определённое слово/слова
Получить диапазон строк
Удалить пустые строки
Заменить пустые строки
Удалить комментарии из кода
Добавить отступы к определённым строках
Изменить начало строки
Создать функцию
sed -e
Добавить запись в конец файла
sed в vim

Введение

Это статья про SED.

Про AWK вы можете прочитать в статье AWK

Про GREP в статье GREP

По умолчанию я предполагаю, что Вы работаете в Bash под Windows 10 или в Bash в Linux .

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

Для того чтобы применить SED достаточно ввести в командную строку

echo ice | sed s/ice/fire/

Результат:

fire

Обратите внимание на то, что использовать / не обязательно.

Вы можете после s поставить какой-то другой символ, например : или , или |

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

echo mice | sed s/m/r/
echo mice | sed s,m,r,
echo mice | sed s:m:r:

rice

Если вы выбрали |, то команду нужно взять в кавычки - у | есть особая роль в bash - pipeline

echo mice | sed 's|m|r|'

rice

Если вы редактируете пути до файлов (а они содержат /) то это как раз тот случай, когда удобно выбрать другой разделитель

Например, нужно заменить /bin/bash на /bin/sh

Намного удобнее использовать @ как разделитель чем экранировать каждый слеш.

Сравните две идентичные команды

sed 's@/bin/bash@/bin/sh@' /etc/passwd

sed 's/\/bin\/bash/\/bin\/sh/' /etc/passwd

Замена слова в файле

Обычно SED применяют к файлам, например к логам или конфигам.

Предположим, что у нас есть файл input.txt следующего содержания

Here is a String Here is an Integer Here is a Float

Мы хотим заменить слово Here на There

sed 's/Here/There/' input.txt

Результат будет выведен в консоль:

There is a String

There is an Integer

There is a Float

Если нужно не вывести в консоль (в stdout) а изменить содержание файла - используем опцию -i

sed -i 's/Here/There/' input.txt

В этом случае перепишется исходный файл input.txt

Хорошей практикой считается сначала проверить свой скрипт без -i и если всё работает верно внести изменения в файл.

С помощью -i.bak можно создать резервный файл (бэкап)

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

Пусть файл input.txt теперь выглядит так:

Here is an Apple. Here is a Pen. Here is an ApplePen Integer is Here Here is a Float Here is a Pen. Here is a Pineapple. Here is a PineapplePen

sed 's/Here/There/' input.txt

Как Вы сейчас увидите, замена произойдёт только по одному разу в строке

There is an Apple. Here is a Pen. Here is an ApplePen

Integer is There

There is a Float

There is a Pen. Here is a Pineapple. Here is a PineapplePen

Чтобы заменить все слова нужна опция g

sed 's/Here/There/g' input.txt

There is an Apple. There is a Pen. There is an ApplePen
Integer is There

There is a Float

There is a Pen. There is a Pineapple. There is a PineapplePen

ApplePen

Замена слова в файле и вывод результата в другой файл

Та же замена, но с выводом в новый текстовый файл, который мы назовём output:

sed 's/Here/There/' input.txt > output.txt

Замена слова в нескольких файлах одновременно

Если нужно обработать сразу несколько файлов: например файл 1.txt с содержанием

First File: Here

И файл 2.txt с содержанием

Second File: Here

Это можно сделать используя *.txt

sed 's/Here/There/' *.txt > output.txt

На выходе файл output.txt будет выглядеть так

First File: There Second File: There

Отбросить всё, что левее определённого слова

Предположим, что у нас есть файл input.txt следующего содержания

Here is a String it has a Name Here is an Integer it has a Name Here is a Float it has a Name

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

sed 's/^.*it//' input.txt > output.txt

^ означает, что мы стартуем с начала строки Результат:

 has a Name

 has a Name

 has a Name

Для доступности объясню синтаксис сравнив две команды. Посмотрите внимательно, когда мы заменяем слово Here на There.

There находится между двумя слэшами. Раскрашу их для наглядности в зелёный и красный.

sed 's/Here/There/'

А когда мы хотим удалить что-то, мы сначала описываем, что мы хотим удалить. Например, всё от начала строки до слова it.

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

sed 's/^.*it//' > output.txt

Отбросить всё, что правее определённого слова

Предположим, что у нас есть файл input.txt следующего содержания

Here is a String / it has a Name Here is an Integer / it has a Name Here is a Float / it has a Name

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

sed 's/is.*//' > output.txt

Результат:

Here Here Here

Экранирование символов в sed

Специальные символы экранируются с помощью \;

Что включать в специальные символы зависит от того, какой sed вы используете, но $.*[\^ а также пробелы и кавычки советую экранировать всегда.

Пробел также можно заменять на \s

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

heihei\.ru

Пример экранирования точек и кавычек для смены локали в CentOS можете изучить здесь

Предположим, что есть файл input.txt следующего содержания

Here is a String / it has a Name Here is an Integer / it has a Name Here is a Float it / has a Name

Мы хотим отбросить всё, что находится левее /a, включая /a, и записать в файл.

sed 's/^.*/a//' > output.txt

В результате получим ошибку

-e expression #1, char 15: unknown option to `s'

Чтобы команда заработала нужно добавить \ перед /

sed 's/^.*\/a//' > output.txt

Результат:

Here is a String Here is an Integer Here is a Float

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

Чтобы в скрипте sites.sh из директории /opt/andrei/scripts/ заменить фразу Bike website topbicycle.ru на Travel website heihei.ru нужно выполнить

sed -i s/Bike\ website\ topbicycle.ru/Travel\ website\ heihei.ru/ /opt/andrei/scripts/sites.sh

Два условия одновременно в Sed

Предположим, что у нас есть файл input.txt следующего содержания

Here is a String /b it has a Name Here is an Integer /b it has a Name Here is a Float /b it has a Name

Мы хотим отбросить всё, что находится левее /b, включая /b, и всё, что правее has.

Таким образом, в каждой строчке должно остаться только слово it.

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

sed 's/^.*\/b// ; s/has.*//' input.txt > output.txt

Результат:

it it it

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

sed ':a;N;$!ba;s/\n//g' file ;

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

Допустим Вы хотите удалить все строки после третьей

sed 3q input.txt > output.txt

Удалить первые несколько строк

Допустим Вы хотите удалить три первые строки файла example.txt

sed -i -e 1,3d example.txt

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

Удалить третью строку в файле test.txt

sed -i 3d test.txt

Удалить строку со словом

Удалить все строки где встречается слово Apple в файле input.txt

Here is an Apple Here Pen Here ApplePen Integer is Here Here is a Float Here Pen Here Pineapple Here PineapplePen Umm Apple Apple Apple Pen

Сделать это можно с помощью опции d

sed '/Apple/d' input.txt > output.txt

Результат:

Integer is Here Here is a Float Here Pen Here Pineapple Here PineapplePen

Теперь сделаем более сложное условие - удалим все строки где есть слово Pineapple и слово Integer

sed '/Pineapple\|Integer/d' input.txt > output.txt

| выступает в роли логического ИЛИ

\ нужна чтобы экранировать |

Результат:

Here is an Apple. Here is a Pen. Here is an ApplePen Here is a Float Umm Apple Apple Apple Pen

Получить диапазон строк

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

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

Например, Вам нужны строки с 9570 по 9721

sed -n '9570,9721p;9722q' project-2019-10-03.log > bugFound.txt

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

Если строка действительно пустая, то подойдёт команда

sed '/^$/d'

Обычно жизнь более жестока, и в строках содержатся пробелы.

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

$ sed '/^[[:space:]]*$/d' input.txt > output.txt

Заменить пустые строки

Заменить все пустые строки на двойные тэги переноса строки

$ sed 's/^[[:space:]]*$/\<br\>\<br\>/' input.txt > output.txt

Заменить всё между определёнными символами

Удалить всё что находится между квадратными скобками включая скобки

sed 's/\[.*\]//' input.txt > output.txt

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

Допустим, у вас есть код или просто текст в котором много комментариев.

Строка с комментариями начинается с символа #

Рассмотрим файл websites

cat websites

# Travel https://www.heihei.ru # Bicycles https://www.topbicycle.ru # IT https://www.urn.su

Чтобы удалить строки с комментариями выполните

sed -i '/^#/d' websites

Опция -i позволяет изменять текущий файл

Если хотите сохранить исходный файл а текст без комментариев записать в новы (если вы уже удалили комментарии - убедитесь, что вы их вернули обратно)

sed '/^#/d' websites > nocomments
cat nocomments

https://www.heihei.ru https://www.topbicycle.ru https://www.urn.su

Опция -i не нужна так как исходный файл мы не изменяли

Чтобы удалить строки с комментариями и пустые строки выполните

sed -i '/^#/d ; /^$/d' websites

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

Рассмотрим файл input.txt

cat input.txt

lex red red test red muha lex red red lex red lex blue

На начало строки указывает символ ^

Заменим red на yellow, но не везде, а только там где строка начинается с lex

sed -i '/^lex/ s/red/yellow/' input.txt

cat input.txt

lex yellow red test red muha lex red red lex yellow lex blue

Создать функцию

Чтобы каждый раз не вспоминать команды sed можно создать функцию

Возьмём команду, которая удаляет комментарии и пустые строки из предыдущего примера и запишем как функцию clean_file.

Первым делом в коносли нужно написать в терминале function clean_file { и нажать Enter

Затем ввести выражение sed -i '/^#/d ; /^$/d' $1

$1 означает, что функция будет принимать один аргумент. Это, конечно, будет название файла.

Затем нужно снова нажать Enter и в новой строке написать } и нажать Enter ещё раз

$ function clean_file { > sed -i '/^#/d;/^$/d' $1 > }

Убедитесь, что файл содержит комментарии и пустые строки. Если нет - создайте для чистоты эксперимента.

cat websites

# Travel https://www.heihei.ru # Bicycles https://www.topbicycle.ru # IT https://www.urn.su

clean_file websites
cat websites

https://www.heihei.ru https://www.topbicycle.ru https://www.urn.su

Контакты и сотрудничество:
Рекомендую наш хостинг beget.ru
Пишите на info@urn.su если Вы:
1. Хотите написать статью для нашего сайта или перевести статью на свой родной язык.
2. Хотите разместить на сайте рекламу, подходящуюю по тематике.
3. Реклама на моём сайте имеет максимальный уровень цензуры. Если Вы увидели рекламный блок недопустимый для просмотра детьми школьного возраста, вызывающий шок или вводящий в заблуждение - пожалуйста свяжитесь с нами по электронной почте
4. Нашли на сайте ошибку, неточности, баг и т.д. ... .......
5. Статьи можно расшарить в соцсетях, нажав на иконку сети: