#begin command block
#append all lines between two addresses to hold space
sed -n -f - <<\SCRIPT file.xml
\|<tag1>|,\|</tag1>|{ H
#at last line of search block exchange hold and pattern space
\|</tag1>|{ x
#if not conditional ; clear buffer ; branch to script end
\|<tag2>[^<]*foo[^\n]*</tag2>|!{s/.*//;h;b}
#do work ; print result; clear buffer ; close blocks
s?*?*?;p;s/.*//;h;b}}
SCRIPT
Если вы сделаете выше, учитывая данные, которые вы показываете, перед последней строкой очистки, вы должны работать с sedпространством шаблона, которое выглядит следующим образом:
^\n<tag1>\n<tag2>foo</tag2>\n</tag1>$
Вы можете распечатать свое пространство шаблона в любое время с помощью lOok. Затем вы можете обратиться по \nсимволам.
sed l <file
Покажет вам каждая строка sedобрабатывает ее на этапе, на котором lвызывается.
Итак, я только что проверил его, и он нуждался в еще одном \backslashпосле ,commaпервой строки, но в остальном работает как есть. Здесь я поместил это в _sed_functionтак, чтобы я мог легко вызвать это для демонстрационных целей в течение этого ответа: (работает с включенными комментариями, но здесь удален ради краткости)
_sed_function() { sed -n -f /dev/fd/3
} 3<<\SCRIPT <<\FILE
\|<tag1>|,\|</tag1>|{ H
\|</tag1>|{ x
\|<tag2>[^<]*foo[^\n]*</tag2>|!{s/.*//;h;b}
s?*?*?;p;s/.*//;h;b}}
#END
SCRIPT
<tag1>
<tag2>bar</tag2>
</tag1>
<tag1>
<tag2>foo</tag2>
</tag1>
FILE
_sed_function
#OUTPUT#
<tag1>
<tag2>foo</tag2>
</tag1>
Теперь мы переключим параметр pна, lчтобы мы могли видеть, с чем мы работаем, когда мы разрабатываем наш сценарий, и удаляем неоперационную демонстрацию, s?чтобы последняя строка нашего sed 3<<\SCRIPTкода выглядела так:
l;s/.*//;h;b}}
Тогда я запустлю это снова:
_sed_function
#OUTPUT#
\n<tag1>\n <tag2>foo</tag2>\n</tag1>$
ОК! Так что я был прав - это хорошее чувство. Теперь давайте перетасуем наш look, чтобы увидеть строки, которые он вытягивает, но удаляет. Мы удалим наш текущий lи добавим один к !{block}так, чтобы это было похоже на:
!{l;s/.*//;h;b}
_sed_function
#OUTPUT#
\n<tag1>\n <tag2>bar</tag2>\n</tag1>$
Вот как это выглядит перед тем, как мы уничтожим это.
И последнее, что я хочу показать вам, это Hстарое пространство, в котором мы его строим. Есть пара ключевых концепций, которые я надеюсь продемонстрировать. Поэтому я lснова удаляю последний ook и изменяю первую строку, чтобы добавить заглядывание в Hстарое пространство в конце:
{ H ; x ; l ; x
_sed_function
#OUTPUT#
\n<tag1>$
\n<tag1>\n <tag2>bar</tag2>$
\n<tag1>\n <tag2>bar</tag2>\n</tag1>$
\n<tag1>$
\n<tag1>\n <tag2>foo</tag2>$
\n<tag1>\n <tag2>foo</tag2>\n</tag1>$
Hстарое пространство переживает линейные циклы - отсюда и название. Так что люди часто сбиваются с толку - хорошо, то, что я часто сбиваю с толку - это то, что его нужно удалить после того, как вы его используете. В этом случае я могу xизменить только один раз, поэтому пространство удержания становится пространством шаблона и наоборот, и это изменение также сохраняется в циклах строк.
Эффект заключается в том, что мне нужно удалить мое пространство удержания, которое раньше было моим пространством образца. Я делаю это, сначала очистив пространство текущего шаблона с помощью:
s/.*//
Который просто выбирает каждого персонажа и удаляет его. Я не могу использовать, dпотому что это завершит мой текущий цикл строки, а следующая команда не будет выполнена, что в значительной степени испортит мой сценарий.
h
Это работает аналогично, Hно перезаписывает пространство удержания, поэтому я просто скопировал пустое пространство шаблона поверх моего пространства удержания, фактически удалив его. Теперь я могу просто:
b
вне.
И вот как я пишу sedсценарии.