Программа обрабатывает многострочные буферы целиком командами
редактирования, слегка похожие на команды программы sed. Имеет
дополнительный и стек буферов, счётчик и поддерживает динамически
сформированные регулярные выражения, позволяющие искать вложение блоков.
Поиск и замены производятся и для нулевого символа \000 и для символов
перевода строки \n, но для этого во входных файлах должно не оказаться
вплоть до двух неиспользованных байтов. Regex-ы имеют расширенный формат по
умолчанию и поддерживают нежадный синтасис, например, .*?. Имена файлов для
подгрузки файлов и выгрузки в файлы буферов в процессе работы также можно
формировать динамически.
Команды без аргументов могут быть склеены в одно слово и быть префиксом
к комплексной команде поиска, сравнения и замен.
- #комментарии до конца строки;
Общий формат команд замен, возможно, с предварительным поиском
регулярного выражения:
- (cmd[mod]*)+ [delim](arg[delim])+
Аргумент команд после необязательных пробельных символов начинается
символом-разделителем, который может быть любым непробельным, кроме
обратного слеша \ и #. Выбор данного символа должен учитывать, что если он
содержится в аргументах, то для экранирования его обратным слешем он не
должен совпадать с символами специального кодирования (см. ниже). Если
пробелы перед аргументами отсутствуют, то символ-разделитель будет первым
не из диапазона команд и модификаторов: ABCHIMNPQRWaceikmnosw.
Далее в документе используется /. Также далее и выше специальные символы
()[]+*? соотвествуют значениям при составлении шаблонов regex, так символ
'?' указывает на необязательность модификатора.
- RI?o? /regex/ — команда поиска по regex. Дальнейшие
команды замен, склеенные без пробела выполняются при успешном поиске.
модификаторы команды R:
- I — игнорировать регистр букв во входном буфере для
поиска regex;
- o — повторять при успешном поиске комплексную
команду начиная с команды R с этой опцией до конца команды, то есть
пропуская команды предварительной инициализации до R. Результирующий флаг
успешности поиска после цикла с поиском и заменами этой комплексной
командой определяет значение флага самого первого поиска в этом цикле.
Команды замен буферов и счётчика:
- aH? /replace/ — добавить replace к входному
буферу;
- cH? /replace/ — заменить входной буфер на
replace;
- iH? /replace/ — вставить replace в начало входного
буфера;
модификатор команд
- H — помещает в счётчик количество замен перевода
регистра при использовании в replace кодов \l или \u
- AH?o? /replace/ — добавить к выходному буферу
replace;
- CH?o? /replace/ — заменить выходной буфер на replace;
модификатор команд
- o — печать буфер вывода, то есть выполняет команду
p
- PH?k? /replace/ — заменить добавочный буфер
на replace.
модификатор команды P:
- m /var_name/ — заменить добавочный буфер
на значение переменной окружения var_name;
- wH? /line/ — поместить выходной буфер в файл
с именем line;
модификатор команды w:
- H — открывает указанный файл на дозапись
- n /line/ — поместить в счётчик длину полученной
строки в символах;
- B /line/ — поместить в счётчик длину полученной
строки в байтах;
- O /line/ — поместить в счётчик значение кода
первого символа line;
- N /set_count/ — команда изменения внутреннего
счётчика. Текстовая строка set_count может содержать в конце простую
арифметическую операцию:
- +N — увеличить значение числа,
получившегося после текстовых замен на число N, например,
N /\c+\c/ удвоит счётчик;
- -N — уменьшить на число N;
- *N — умножить на число N;
- /N — разделить на число N;
- &N — побитовое "и" с числом N;
- |N — побитовое "или" с числом N.
- M /cmp/ — команда сравнения счётчика и возможно с
установкой результата при кодировании с :флагом. cmp кодируется также как и
set_count в команде N. Команда выставляет флаги для перехода по
условиям t|F|G|g|L|l и меняет флаг успешности поиска, если
выполняется после успешного R на неуспешность, если счётчик и
cmp неэквивалентны.
Дополнительно к кодированию set_count вместо арифметической операции
можно использовать следующие код флага записи в счётчик результата
сравнения:
- :t — поместить в счётчик 1, если равно и 0 если не равно
cmp;
- :F — поместить в счётчик 0, если равно и 1 если не равно
cmp;
- :G — поместить в счётчик 1, если счётчик больше cmp и 0 если
меньше либо равно;
- :L — поместить в счётчик 1, если счётчик меньше cmp и 0 если
больше либо равно;
- :g — поместить в счётчик 1, если счётчик больше либо равно
cmp и 0 если меньше;
- :l — поместить в счётчик 1, если счётчик меньше либо равно
cmp и 0 если больше.
- V /line/ — вызвать перекодировку входного буфера
через iconv, где в line указывается перекодирование по формату /из:в/ или
/из/ или /:в/. Если одна из кодировок не указана, то используется текущая
кодировка из переменных окружения LC_ALL|LC_CTYPE|LANG.
Успешность перекодировки зависит от возможности замен всех входных
символов на выходные. При невозможности замены программа записывает в
счётчик количество замен на символ '?' для проблемных символов и
осуществляется переход по метке при вызове команды ? label. При
успешности перекодировки счётчик не меняется, а команда v label
осуществляет переход по метке;
- e /line/ — вывести line в стандартный вывод ошибок
stderr. Программа продолжит работу, но при завершении код возврата будет
равен 1;
- W /NN:line/ — поместить в выходной буфер
разрезанную с помощью \n по ширине NN line;
- T /line/ — поместить в выходной буфер текущее время
по формату strftime, заданный в line. Описание формата см. в man 3
strftime;
- Q /line/ — завершить выполнение программы с кодом
возварата указанном в line;
- sI?H? /regex/replace/ — Циклический поиск regex с
добавлением во внутренний накопитель начала текста до regex, замену regex
на replace, замену входного буфера на остаток после regex и повторение
цикла. По окончании цикла производится формирование входного буфера путём
вставки перед остатком заполненного накопителя. Флаг успешности поиска
после окончания цикла определяется, был ли успешным первый поиск с заменой.
Модификаторы команды s:
- I включает поиск без учёта регистра;
- H помещает в счётчик количество замен
перевода регистра при использовании в replace кодов \l или \u.
- z /XY/ — Поиск пары символов по принципу вложенных
скобок, так z /()/ найдет любое выражение (expr) с любым уровнем вложенных
скобок в основном буфере поиска. Буфер может начинаться с любых символов до
первого указаного в команде z, поиск будет успешным только при наличии
правильного соотношения скобок в первом выражении в буфере, а специальные
символы в следующих командах установятся на: \h - как начало буфера
до найденного выражения, \@ - найденное выражение и \z - остальной буфер.
Специальное кодирование /regex/, /replace/, /set_count/, /line/,
/var_name/ и /cmp/:
- \i — поместить все данные из входного буфера (для команд
c и a — до помещения туда информации);
- \p — поместить данные из буфера вывода (для команд
C и A — до помещения туда информации);
- \g — поместить данные из дополнительного буфера (для команды
P — до помещения туда информации);
- \o — поместить имя обрабатываемого файла;
- \@ — поместить всю найденную информацию согласно regex
(аналог & в программе sed);
- \A до \Z — поместить подблок согласно (subregex) с указанным
номерами от первого до 26-го (аналог \1 ... \9 в sed);
- \h — поместить начало буфера до найденной информации
согласно regex;
- \z — поместить конец буфера после найденной информации
согласно regex;
- \l — перевести в нижний регистр (под)строку, закодированную
следующим за этим кодом одним из всех вышеуказанных специальных кодов;
- \u — перевести в верхний регистр (под)строку, закодированную
следующим за этим кодом одним из всех вышеуказанных специальных кодов
(кроме \l);
- \y — неиспользованный байт во входном файле и в указанных
/заменах/, можно применять как символ экранирования для работы с вложенными
структурами в тексте, см. приложенный пример math.bsed;
- \перевод_строки — игнорируется;
- \c — поместить значение счётчика;
- \0 \0[0-7] \0[0-7][0-7] \0[0-7][0-7] — значение байта
в восьмиричной кодировке;
- \a \b \e \f \n \r \t \v — значение байта по правилам
кодирования языков C и bash;
- \d — (только для команд s и R) сокращение от [[:digit:]];
- \\D — (только для команд s и R) сокращение от [^[:digit:]];
- \s — (только для команд s и R) сокращение от [[:space:]];
- \\S — (только для команд s и R) сокращение от [^[:space:]];
- \w — (только для команд s и R) сокращение от [[:alnum:]_];
- \\W — (только для команд s и R) сокращение от [^[:alnum:]_];
- \x[0-9A-Fa-f] \x[0-9A-Fa-f][0-9A-Fa-f] — значение байта
в шестнадцатеричной кодировке;
- \~ — поместить значение флага поиска и точного сравнения со
счётчиком:
- 0 — поиск неуспешен или не равно для сравнения со счётчиком;
- 1 — если поиск успешен или сравнение показало равенство;
- \delim — если delim не вышеуказанные коды, то вставляется
сам символ delim.
Коды \@...\Z \h и \z — результат предыдущего вызова любой
команды R и разрешены для использования только до изменения
входного буфера командами c|a|i|d|s|x|S|V|Y. Символ # внутри /#/
является обычным.
Пример из файла html_filter.bsed
по удалению html-комментариев:
DRoAcRc /<!--/\h/\z/-->/\z/ i /\p/
- D очистит выходной буфер, который будет использован как
накопитель;
- Ro /<!--/ произведёт поиск начала комментариев, дальнейшие
команды будут выполняться при успешном поиске в цикле;
- A /\h/ добавит в накопитель начало буфера до соотвествия
шаблона в предыдущей команде;
- c /\z/ заменит входной буфер остатком после найденного
шаблона;
- R /-->/ произведет поиск окончания комментария;
- c /\z/ заменит входной буфер на остаток после найденного
шаблона;
- i /\p/ по окончании цикла вставит перед остатком входного
буфера заполненый накопитель.
Команды переходов и установки метки
- : label — установить метку для изменения хода
выполнения скрипта путём перехода на следующую за этой меткой команду
командами j|t|F|G|g|L|l. До имени метки пробелы не обязательны,
имя метки заканчивается либо пробельным символом либо началом комментариев
#. Имена меток должны быть уникальными. Зарезервированы имена, начинающиеся
с фигурных скобок { и };
- j label — безусловный переход на метку;
- t label — переход на метку, если предыдущий поиск
командой R было успешным или сравнение счетчика командой M показало
эквивалентность;
- F label — переход на метку, если предыдущий поиск
был неуспешным или сравнение счетчика показало неэквивалентность;
- v label — переход на метку, если предыдущее
перекодирование командой V было успешным, то есть без замен символов на
знаки '?';
- ? label — переход на метку, если предыдущее
перекодирование командой V было неуспешным, то есть c заменами символов на
знаки '?';
- G|g label — переход на метку, если предыдущее
сравнение счетчика M /cmp/ показало, что счётчик больше cmp | либо
больше и равен;
- L|l label — переход на метку, если предыдущее
сравнение счетчика M /cmp/ показало, что счётчик меньше cmp | либо
меньше и равен.
Команды j|(t|F|G|L|g|l|v|?) завершают
работу скрипта с текущим файлом (по своему условию), если метка для
перехода в скрипте не определена командой : label.
- t|F|G|L|g|l|v|? { commands } — выполнить
команды при выполнении условия, закодированного командой;
Команды также могут содержать свои блоки
t|F|G|L|g|l|v|? { commands }. После завершения блока
команд флаги успешности восстанавливаются в значение до выполнения команд
для возможности выполнить следующий блок с другим условием, например,
R /regex/ t { commands1 } F { commands2 }
где
команды commands1 будут выполнены, если regex успешно найдётся, а
commands2 — если неуспешно. Коды \@...\Z \h и \z могут быть
использованы только внутри t-блока до своих команд поиска внутри commands1.
Остальные коды отразят изменения буферов, произошедших после исполнения
команд в блоке.