Sed: руководство: различия между версиями

Содержимое удалено Содержимое добавлено
Строка 1013:
== Продвинутые приемы ==
=== Работа с дополнительным буфером ===
Ранее мы говорили, что Sed работает со входящей строкой в буфере ''pattern space'', однако в Sed есть еще один дополнительный буфер, который позволяет временно хранить строки, который называется ''hold space''.
 
Следующие команды позволяют вам получать доступ к дополнительному буферу.
 
:<code>h</code>/<code>H</code> (от {{lang-en|hold}})
::Копирует/Добавляет содержимое из ''pattern space'' в ''hold space''. Команда <code>H</code> добавит строку к уже имеющемуся содержимому в ''hold space'', отделив новые данные от старых символом перевода строки.
:<code>g</code>/<code>G</code> (от {{lang-en|gap}})
::Копирует/Добавляет содержимое из ''hold space'' в ''pattern space'', т.е. в обратную сторону.
:<code>x</code> (от {{lang-en|exchange}})
::Меняет местами содержимое ''pattern space'' и ''hold space''.
 
Одним из примеров, когда можно воспользоваться буферами, это объединение подряд идущих строк попарно. Реализовать это можно в реализации GNU Sed, где есть возможность относительно просто ссылаться на четные и нечетные строки. Рассмотрим следующий код:
<source lang="bash">
$ printf "%s\n" a b c d | sed -n '1~2h; 2~2 { H; g; s/\n//gp }'
ab
cd
</source>
В этом примере мы посылаем четыре строки, каждая из которых состоит из одной буквы. Мы используем специальную адресацию, которая поддерживается в GNU Sed, позволяющая нам адресовать нечетные строки (<code>1~2</code>) и четные строки (<code>2~2</code>). Когда мы захватываем нечетную строку, то мы просто копируем ее в ''hold space''. Для четных строк мы сначала добавляем ее в ''hold space'' к тому, что сейчас в нем есть, а затем копируем из ''hold space'' в ''pattern space''. По факту мы извлекаем обратно две склеенных строки разделенные переносом строки. Последней командой мы зачищаем все переносы строки и выводим результат на экран. Так как каждая нечетная строка затирает ''hold space'' от предыдущего результата во время копирования, нам не нужно делать никаких дополнительных действий.
 
Еще одна техника с дополнительным буфером, это захват текста абзацами, если они отделены друг от друга пустыми строками. Пусть у нас есть такой текст:
<source lang="">
 
Жил-был поп,
Толоконный лоб.
Пошел поп по базару
Посмотреть кой-какого товару.
 
Навстречу ему Балда
Идет, сам не зная куда.
«Что, батька, так рано поднялся?
Чего ты взыскался?»
 
Поп ему в ответ: «Нужен мне работник:
Повар, конюх и плотник.
А где найти мне такого
Служителя не слишком дорогого?»
</source>
<source lang="bash">
$ sed '/./{H;$!d} ; x ; s/^/\nSTART-->/ ; s/$/\n<--END/' text.txt
 
START-->
Жил-был поп,
Толоконный лоб.
Пошел поп по базару
Посмотреть кой-какого товару.
<--END
 
START-->
Навстречу ему Балда
Идет, сам не зная куда.
«Что, батька, так рано поднялся?
Чего ты взыскался?»
<--END
 
START-->
Поп ему в ответ: «Нужен мне работник:
Повар, конюх и плотник.
А где найти мне такого
Служителя не слишком дорогого?»
<--END
</source>
Главной частью здесь является <code>/./{H;$!d} ; x ;...</code>. Первая команда захватывает не пустые строки до первой пустой. Такой захват происходит из-за <code>$!d</code>, потому что команда <code>d</code> прерывает исполнение обработки текущей строки и начинает новый цикл (Sed переходит на следующую строку и начинает микропрограмму заново), т.е. переход на следующую команду <code>x</code> не произойдет до тех пор, пока Sed не упрется в пустую строку. Когда Sed упирается в пустую строку или конец потока, происходит переход на команду <code>x</code>, который меняет содержимое буферами местами, и мы работаем с накопленной строкой, как с одной большой строкой. В данном примере мы пометили, начало и конец этой строки, чтобы показать, что абзацы захватываются целиком.
 
=== Продвинутые средства адресации в GNU Sed ===