sed программы содержат одну или более sed команд. Программы записываются в файл, который выполняется командой sed с ключом -f
, либо в командной строке первым параметром (без «-» вначале), либо после ключа -e
.
Некоторые sed-команды содержат адрес, либо диапазон адресов. Команды sed записываются одним символом, но могут содержать дополнительные параметры и флаги.
Адресация в sed имеет следующие формы:
-s
или -i
, то с этим адресом совпадают все строки с номером NUMBER для каждого файла.
-i
или -s
.
Выбирает только строки, в которых встречается выражение /REGEXP/ , если ваше выражение содержит «/», вы их должны экранировать обратным слешем «\».
Если «POSIXLY_CORRECT» не определена, то пустое выражение // совпадает с последним найденным выражением команды s///.
Если переменная «POSIXLY_CORRECT» установлена, то пустое регулярное выражение ни с чем не совпадает. Такое поведение определено стандартом POSIX.
(Вместо % можно использовать любой другой символ)
Так-же как и /REGEXP/, но вместо разделителя(слеша) используется %(либо другой символ), если в выражении присутствует разделитель, его необходимо экранировать.
I
используется для того, что-бы выражение было нечувствительно к регистру. (это GNU расширение).
Этот модификатор так-же является GNU расширением.
Он позволяет строить регулярные выражения в многострочном режиме. Обычно в буфере находится всего одна строка(особенно при использовании адресации), и этот модификатор ни на что не влияет. Его влияние заметно только в том случае, если в буфере sed находится сразу несколько строк(это может произойти после применения команд N, G, либо если в буфер была записана область удержания, к которой была применена команда H).
Например: содержимое буфера:
abc\n def\n
(«\n» означает перевод строки)
выражение /f$/ совпадает и с модификатором M
, и без него, но выражение /c$/ совпадает только с модификатором: /c$/ M
, потому-что по умолчанию, sed считает буфер одной строкой, даже если в нём присутствуют символы новой строки.
Если нет адреса, sed обрабатывает все строки.
Если имеется один адрес, sed обрабатывает только строки, которые совпадают с этим адресом.
Если имеются два адреса разделённые запятой(«,»), sed обрабатывает диапазон адресов, с первого адреса, до второго(включительно). Если второй адрес является регулярным выражением, тогда его совпадение проверяется только начиная со следующей строки, после той, с которой совпал первый адрес. Если вы хотите проверять текст с первой строки, но так, что-бы условие окончания диапазона проверялось и в первой строке тоже, используйте GNU расширение:
0, /REGEXP/
такая форма адресации совпадает только с первой строкой, если эта строка совпадает с /REGEXP/ . Обычная адресация(1, /REGEXP/ ) совпадает со всеми строками текста, или до совпадения какой-либо строки с /REGEXP/ , начиная со второй.
Если второй адрес является числом, и оно меньше номера строки совпавшей с первым адресом (или равно ему), то выводится только эта строка.
GNU sed поддерживает следующие расширения адресации:
Добавление символа «!» в конце адресного выражения приводит к его инверсии, с таким выражением совпадает всё, что не совпадает с адресом. Если с адресным выражением совпадают все строки(например его нет), то добавление ! Приводит к тому, что с таким адресом ничего не совпадает.
Для того, что-бы использовать sed, необходимо понимать регулярные выражения ( regexp(RE или для расширенных ERE), для краткости). Регулярное выражение, это шаблон, который проверяется на совпадение с заданной строкой (другими словами, шаблон ищется в данной строке). Проверка производится слева направо.
Многие символы в regexp воспринимаются "как есть": Если мы желаем найти в строке символ «Q», то для поиска потребуется regexp /Q/ . Тривиальный пример: этот regexp - «test» совпадает с теми, и только с теми строками, в которых есть слово «test».
Мощность регулярных выражений определяется тем, что в них могут присутствовать специальные символы, которые позволяют задавать разные критерии совпадений, а так-же повторение символов и подвыражений.
Совпадает любым числом вхождений предыдущего символа или предыдущего регулярного подвыражения(в том числе и его отсутствия). Если вы желаете найти именно символ «*», то его следует за экранировать («\*»).
Расширение GNU: «a**» эквивалентно «a*». Правда это не стандартно, и применять такие конструкции не следует (они могут быть восприняты как «a*\*»).
Для применения постфиксных операций. Например:
/(XY){3}/
совпадает с XYXYXY, но
/XY{3}/
совпадает только с XYYY.
sed 's/./Z/'(описание sed-команды s см.ниже, в данном случае sed просто поменяет шаблон /./ на "Z").
$ echo "A" | sed 's/./Z/' Z # самое простое - я дал sed один символ, и она его поменяла. $ echo "ABCDE" | sed 's/./Z/' ZBCDE # в данной строке меняется только первый символ(с помощью модификаторов s (см. ниже) # это поведение можно изменить) $ echo "" | sed 's/./Z/' # пустая строка не изменилась, в этом случае выполнение команды s не так просто - # дело в том, что я просил "найти любой символ", но она не смогла этого сделать # (т.к. символов вообще нет), потому замены не было, и строка осталась без # изменения.
$ echo 'ABCD' | sed -r 's/(^).*/\1/' # ответ - пустая строка. Здесь я заменил всю строку на внутренность в скобках (^)В оригинале есть и такой пример:
/^#include/это выражение отыщет все строки, которые начинаются на «#include», те строки которые не начинаются на «#include» будут проигнорированы, даже если перед «#include» стоят только пробелы. Для совместимости, не следует использовать «^» в начале подвыражений, так-как POSIX стандарт трактует этот символ как обычный в данном контексте.
(drBatty):
Моя версия(4.0.9), похоже всегда считает этот символ специальным, даже тогда, когда использование его как спецсимвол не имеет смысла (например /.^/ ). Потому, если вы хотите искать именно «^», в RE его необходимо экранировать. Кроме того, тут почему-то не сказано про "многострочный" режим(модификаторы I
, для адресного RE, и m
для команды s (об этом сказано чуть выше)).
Совпадает с единственным символом из СПИСКА. Для примера, RE
/[aeiou]/
совпадает только с одной из маленьких гласных нерусских букв. Список может включать диапазоны символов, например /[0-9]/ совпадает с любой цифрой, возможны и более сложные конструкции, например /[0-9A-Fa-f]/ совпадает с любой шестнадцатеричной цифрой. Если перед СПИСКОМ стоит «^», то СПИСОК инвертируется, он совпадёт с любым символом не из этого СПИСКА.
Символы «$», «*», «.», «[», и «\» не имеют специального значения внутри СПИСКА. Для примера, /[\*]/ совпадает с «\» или с «*», потому-что «\» не имеет специального значения в этом контексте. А дальше фигня какая-то написана про специальные символьные классы(выше я писал про обычные [СПИСОК] и [^СПИСОК]), приведу без перевода:
However, strings like `[.ch.]', `[=a=]', and `[:space:]' are special within LIST and represent collating symbols, equivalence classes, and character classes, respectively, and `[' is therefore special within LIST when it is followed by `.', `=', or `:'. Special escapes like `\n' and `\t' are recognized within LIST; this will change in a future version in `POSIXLY_CORRECT' mode. *Note Escapes::
На самом деле, «\n» и «\t» внутри списка действительно могут присутствовать (в т.ч. и некоторые другие, например «\a»), а что касается спец-классов, то тут как раз тот редкий случай, когда лучше почитать ВАШ man 7 regex, там более подробная и правильная информация. Которая, впрочем может тоже не подойти к ВАШЕЙ реализации sed(особенно, если вы взяли свою sed откуда-то слева) например у меня поддерживаются следующие классы(хотя я не все проверял)
alnum digit punct alpha graph space blank lower upper cntrl print xdigit
На самом деле, я недолюбливаю эти спец-классы: никогда точно не знаешь, какие именно символы данная конкретная реализация считает непечатными, и какие именно символы считаются большими буквами(вопрос совсем не тривиальный, если буквы русские). ИМХО в правильно настроенной системе текст в «правильной» кодировке будет корректно обрабатываться командой sed. Однако... Проблема в том, что за кодировки отвечает несколько переменных, и они могут иметь различное значение, потому команда "iconv -f КОДИРОВКА" должна вообще-то преобразовать из какой-то КОДИРОВКИ в родную, которая затем должна быть нормально и читаемо вывестись на экран, при этом, я могу с помощью sed скажем заменить все большие русские буквы на малые, и это всё должно быть нормально видно... Но... Я предпочитаю написать просто [а-яА-Я] для поиска любой русской буквы, чем потом удивляться.
(кстати, не все русские кодировки поддерживают такие диапазоны - к сожалению, в некоторых есть "дыры", т.е. [а-я] включает НЕ ТОЛЬКО русские буквы). См. также.
$ echo 'ABCDEF' | sed -r 's/D|C/W/' ABWDEF $ echo 'ABCDEF' | sed -r 's/C|D/W/' ABWDEFКак видите, оба шаблона ( /C|D/ и /D|C/ ) находят первую встреченную букву (C в данном случае).
$ echo 'ABCDEFGH' | sed -r 's/C.+|CDE/W/' ABW $ echo 'ABCDEFGH' | sed -r 's/CDEF|C.+/W/' ABWВидно, что захватывает символы подвыражение /C.+/ См. также
$ echo 'ABCDEFGH' | sed -r 's/.*\1.*(C).*/FOUND/' sed: -e выражение #1, символ 20: Invalid back reference # Ошибка. Обратная ссылка не может указывать на выражение правее её. $ echo 'ABCDEFCGH' | sed -r 's/.*(.).*\1.*/FOUND/' FOUND # Ещё раз, и медленно :-) # 1) любое количество любых символов # 2) любой одиночный символ # 3) любое количество любых символов # 4) символ, такой-же, как был найден в пункте 2 # 5) любое количество любых символов # Это очень нужное RE, и оно часто применяется. В данном случае важны пункты # 2 и 4 - в пункте 2 находится любой символ, а в пункте 4 находится точно такой-же # т.о. это RE совпадает только со строками в которых есть хотя-бы 2 одинаковых # символа. Причём не важно, что-это за символы. Кроме того, неважно,что находится # до, между, и после этих символов(в данном случае). $ echo 'ABCDEFGH' | sed -r 's/.*(.).*\1.*/FOUND/' ABCDEFGH # В данном случае одинаковых символов нет, поэтому строка не меняется. $ echo 'ABcdEFdGcH' | sed -r 's/.*(.).*\1.*/\1/' d $ echo 'ABcdEFGcHd' | sed -r 's/.*(.).*\1.*/\1/' d # в отличие от других случаев, обратные ссылки находят не первое, а ПОСЛЕДНЕЕ # совпадение. Т.е., если у нас есть(как в этом примере) # cd****строка в которой есть и c и d в любом порядке(хвост)**** # то отыщется именно d. # однако, это касается только случая, если в (хвосте) нету других одинаковых пар # если они там есть, результат будет иным: $ echo 'ABcdEFGccHd' | sed -r 's/.*(.).*\1.*/\1/' c $ echo 'ABcdEFGttHd' | sed -r 's/.*(.).*\1.*/\1/' t
Примеры:
/abcdef/
Совпадает с `abcdef'.
/a*b/
Совпадает с нулевым или большим количеством символов «a» после которых следует одиночный символ «b». Для примера, «b» или «aaaaab».
/a?b/
Совпадает с «b» или с «ab».
/a+b+/
Совпадает с одним(или с большим числом) символов «a» после которого идёт один, либо большее число символов «b». «ab» это самое короткое совпадение, другие совпадения: «aaaab» или «abbbbb» или «aaaaaabbbbbbb».
/.*/
/.+/
Оба этих выражения совпадают со всеми символами в строке; первое выражение отличается тем, что оно совпадает в т.ч. и с пустыми строками. Второе выражение совпадает лишь с теми строками, в которых имеется хотя-бы один символ. (см. ограничения sed пункт 1.б)
/^main.*\(.*\)/
Это ERE совпадает с любой строкой, которая начинается на «main», после чего содержит любое количество любых символов.
после чего идёт открывающая скобка «(», ещё некоторое количество символов(или без символов), в затем, закрывающая скобка( «)» ).
/^\#/
Совпадает со строками, которые начинаются на «#».
/\\$/
Это RE совпадает со строками, в конце которых стоит обратный слеш ( «\» ). RE содержит два обратных слеша для экранирования.
/\$/
Это RE совпадает с любой строкой, в которой имеется хотя-бы один символ «$».
/[a-zA-Z0-9]/
В английской локали, это выражение совпадает с любой буквой, либо с любой цифрой.
/[^ tab]+/
(тут `tab' означает единственный символ табуляции.) Это выражение совпадает с одним, либо большим числом символов, равных пробелу либо табуляции. Эти символы обычно разделяют слова в предложениях.
/^(.*)\n\1$/
Это выражение совпадает с любыми двумя одинаковыми строкам, которые разделены символом новой строки.
/.{9}A$/
Это выражение совпадает с девятью любыми символами, после которых стоит символ `A'.
/^.{15}A/
Это выражение совпадает с любой строкой, которая длиннее 15и символов, и кроме того, 16м символом должен быть символ 'A'.
`sed' работает с (двумя? неа!) с одним буфером для данных. Второй буфер зарезервирован в большинстве обычных операций, sed читает входной поток в буфер, обрабатывает его, и выводит результат туда-же. В некоторых случаях sed выводит результат в stdout, но НИКОГДА не выводит в "буфер2". Буфер2 изначально инициализирован пустой строкой ("\n"). Он используется для сохранения промежуточных результатов между обработкой строк (если кодеру ЭТО надо). Лишь немногие команды ('h', 'H' и 'x') имеют доступ (для модификации) к "буферу2". Впрочем для чтения из "буфера2" так-же немного команд ('x', 'g', и 'G'). В оригинале, буфер2 называется "hold space".
Вы можете обсудить этот документ на форуме. Текст предоставляется по лицензии GNU Free Documentation License (Перевод лицензии GFDL).
Вы можете пожертвовать небольшую сумму яндекс-денег на счёт 41001666004238 для оплаты хостинга, интернета, и прочего. Это конечно добровольно, однако это намного улучшит данный документ (у меня будет больше времени для его улучшения). На самом деле, проект часто находится на грани закрытия, ибо никаких денег никогда не приносил, и приносить не будет. Вы можете мне помочь. Спасибо.