Есть несколько способов сделать это с помощью sed
. Один из способов - отложенное чтение, как рекомендуется в принятом ответе. Это также можно записать как:
sed -e '$!N;P;/\nPointer/r file1' -e D file2
... с небольшим явным просмотром вперед вместо просмотра назад, реализованного в другом месте с буфером удержания. Однако в этом случае неизбежно возникнет та же проблема с последней строкой, которую отмечает @don_crissti, поскольку N
does инкрементирует цикл строки, а команда r
ead применяется по номеру строки.
Это можно обойти:
echo | sed -e '$d;N;P;/\nPointer/r file1' -e D file2 -
Не все sed
ы будут интерпретировать -
как стандартный ввод, но многие это делают. (POSIX говорит sed
должен поддерживать -
как стандартный ввод, если исполнитель хочет, чтобы -
означали стандартный ввод???)
Другой способ - обрабатывать добавляемое содержимое по порядку. Есть еще одна команда, которая schedules выводит так же, как r
ead, а sed
применит ее и r
ead в том порядке, в котором они прописаны в сценарии. Однако это немного сложнее - это подразумевает использование одного sed
для a
ppend Pointer
совпадения с выводом другого sed
в своем сценарии.
sed ' /Pointer/!d #only operate on first match
s/[]^$&\./*[]/\\&/g;H #escape all metachars, Hold
s|.*|/&/!p;//!d|p;g #print commands, exchange
s|.|r file1&a\\&|;q' file2| #more commands, quit
sed -nf - file2 #same input file
То есть, по сути, первый sed
пишет второму sed
скрипт, который второй sed
читает на стандартном входе (возможно...) и применяет по очереди. Первый sed
работает только при первом найденном совпадении для Pointer
, после чего q
uits input. Его задача состоит в том, чтобы...
s/[]^$&\./*[]/\\\&/g;H
sed
должен будет интерпретировать каждый прочитанный бит буквально, чтобы все было правильно. Как только это будет сделано, поместите копию в H
old space. s|.*|/&/!p;//!d|p; x
sed
, чтобы p
rint каждую строку ввода !
кроме той /&/
, которую мы только что проверили по шаблону; а затем d
elete all of the same. p
rint команды на втором sed
, затем ex
change h
old и pattern buffers для работы с нашей сохраненной копией. s|.|r file1&a\\\\&|p;q
\n
ewline, потому что sed
добавит его, когда мы H
eld строку до этого. Поэтому мы вставляем команду r file1
, за ней следует \n
ewline, затем команда a\\\
для a
ppend, за которой также следует \n
ewline. Вся остальная часть нашей строки H
eld следует за этой последней \n
ewline. Скрипт, который пишет первый, выглядит примерно так:
/Pointer-file2 "23"/!p;//!d
r file1
a\
Pointer-file2 "23"
В основном второй sed
будет печатать все строки, кроме той, которую первый sed
установил на a
ppend. Для этой конкретной строки две отложенные записи в standard-out будут запланированы - первая будет r
началом file1
, а вторая - копией строки, которую мы хотим получить после неё. Первый sed
в данном случае даже не нужен (видите? без обратных слешей), но важно безопасно экранировать так, как я это делаю здесь, всякий раз, когда совпадение шаблонов используется в качестве входных данных.
В любом случае... есть несколько способов.