Подтвердить что ты не робот

Концепция "Hold space" и "Pattern space" в sed

Я смущен двумя понятиями в sed: удержание пространства и пространства шаблонов. Может кто-нибудь помочь объяснить их?

Вот фрагмент руководства:

h H    Copy/append pattern space to hold space.
g G    Copy/append hold space to pattern space.

n N    Read/append the next line of input into the pattern space.

Эти шесть команд действительно путают меня.

4b9b3361

Ответ 1

Когда sed читает файл строки за строкой, строка, которая была прочитана в настоящее время, вставляется в буфер шаблона (пространство шаблонов). Буфер шаблонов похож на временный буфер, блокнот, в котором хранится текущая информация. Когда вы сообщаете sed для печати, он печатает буфер шаблонов.

Удержание буфера/удержания - это как долговременное хранилище, так что вы можете что-то поймать, сохранить его и повторно использовать позже, когда sed обрабатывает другую строку. Вы напрямую не обрабатываете пространство удержания, вместо этого вам нужно скопировать его или добавить в пространство шаблонов, если вы хотите что-то с ним сделать. Например, команда print p печатает только пространство с рисунком. Аналогично, s работает на пространстве шаблонов.

Вот пример:

sed -n '1!G;h;$p'

(опция -n подавляет автоматическую печать строк)

Здесь есть три команды: 1!G, h и $p. 1!G имеет адрес, 1 (первая строка), но ! означает, что команда будет выполняться всюду, но в первой строке. $p, с другой стороны, будет выполняться только в последней строке. Итак, что происходит:

  • первая строка считывается и автоматически добавляется в пространство шаблонов
  • в первой строке первая команда не выполняется; h копирует первую строку в пространство удержание.
  • теперь вторая строка заменяет все, что было в пространстве шаблонов
  • во второй строке, сначала мы выполним G, добавив содержимое буфера удержания в буфер шаблона, разделив его на новую строку. Теперь пространство шаблонов содержит вторую строку, новую строку и первую строку.
  • Затем команда h вставляет конкатенированное содержимое буфера шаблона в пространство удержания, которое теперь содержит обратные строки два и один.
  • Переходим к строке номер три - переходим к точке (3) выше.

Наконец, после того, как последняя строка была прочитана, и пространство удержания (содержащее все предыдущие строки в обратном порядке) было добавлено к пространству рисунка, пространство с рисунком печатается с помощью p. Как вы уже догадались, вышесказанное делает именно то, что делает команда tac - печатает файл в обратном порядке.

Ответ 2

@Эд Мортон: я не согласен с вами здесь. Я обнаружил, что sed очень полезен и прост (когда вы понимаете концепцию шаблона и удерживаете буферы), чтобы придумать элегантный способ выполнения многострочного поиска.

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

Host: foo1
some junk, doesnt matter
some junk, doesnt matter
Info: about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Info: a second line about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Host: foo2
some junk, doesnt matter
Info: about foo2 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter

Для меня сценарий awk для получения строк с именем хоста и соответствующей info строкой занял бы немного больше, чем то, что я могу сделать с помощью sed:

sed -n '/Host:/{h}; /Info/{x;p;x;p;}' myfile.txt

вывод выглядит так:

Host: foo1
Info: about foo1 that I really care about!!
Host: foo1
Info: a second line about foo1 that I really care about!!
Host: foo2
Info: about foo2 that I really care about!!

(Обратите внимание, что Host: foo1 появляется дважды в выводе.)

Объяснение:

  1. -n отключает вывод, если явно не напечатано
  2. первое совпадение, находит и помещает строку Host: в буфер удержания (h)
  3. во втором совпадении находит следующую строку Info:, но сначала обменивается (x) текущей строкой в буфере шаблонов с буфером удержания, и печатает (p) строку Host: затем повторно обменивается (x) и печатает (p) Info: линия.

Да, это упрощенный пример, но я подозреваю, что это общая проблема, с которой быстро справился простой однострочник sed. Для гораздо более сложных задач, таких как задачи, в которых вы не можете полагаться на заданную, предсказуемую последовательность, может лучше подойти awk.

Ответ 3

Хотя ответ @января и пример хороши, объяснения мне не хватило. Мне пришлось много искать и учиться, пока я не понял, как именно работает sed -n '1!G;h;$p'. Поэтому я хотел бы уточнить команду для кого-то вроде меня.

Прежде всего, давайте посмотрим, что делает команда.

$ echo {a..d} | tr ' ' '\n' # Prints from 'a' to 'd' in each line
a
b
c
d
$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;$p'
d
c
b
a

Он изменяет ввод, как это делает команда tac.

sed читает строку за строкой, так что давайте посмотрим, что происходит в области patten и в области hold в каждой строке. Поскольку команда h копирует содержимое пространства образца в пространство удержания, оба пространства имеют одинаковый текст.

Read line    Pattern Space / Hold Space    Command executed
-----------------------------------------------------------
a            a$                            h
b            b\na$                         1!G;h
c            c\nb\na$                      1!G;h
d            d\nc\nb\na$                   1!G;h;$p

В последней строке $p выводит d\nc\nb\na$ отформатированный в

d
c
b
a

Если вы хотите увидеть шаблонное пространство для каждой строки, вы можете добавить команду l.

$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;l;$p'
a$
b\na$
c\nb\na$
d\nc\nb\na$
d
c
b
a

Мне было очень полезно посмотреть этот видеоурок. Понимание того, как работает sed, поскольку парень показывает, как каждое пространство будет использоваться шаг за шагом. Интервал удержания указан в четвертом уроке, но я рекомендую посмотреть все видео, если вы не знакомы с sed.

Также документ GNU sed и учебник Bruce Barnett Sed являются очень хорошими ссылками.