SED
Введение
Это статья про 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

Замена слова в файле и вывод результата в другой файл
Та же замена, но с выводом в новый текстовый файл, который мы назовём 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
Создать функцию
Чтобы каждый раз не вспоминать команды 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