Как я могу вставить содержимое файла в другой файл прямо перед определенной строкой

Как я могу вставить содержимое файла в другой файл прямо перед определенной строкой, используя sed?

Например, у меня есть файл file1.xml, который имеет следующее:

        <field tagRef="376">
        </field>
        <field tagRef="377">
        </field>
        <field tagRef="58">
        </field>
        <group ref="StandardMessageTrailer" required="true"/>
    </fieldList>
</message>

и file2.xml имеет следующее:

        <field tagRef="9647">
            <description>Offset</description>
        </field>
        <field tagRef="9648">
            <description>Offset Units/Direction</description>
        </field>
        <field tagRef="9646">
            <description>Anchor Price</description>
        </field>

как я могу вставить содержимое файла2 в файл1 непосредственно перед

<group ref="StandardMessageTrailer" required="true"/>

поэтому это будет выглядеть так:

       <field tagRef="376">
        </field>
        <field tagRef="377">
        </field>
        <field tagRef="58">
        </field>
        <field tagRef="9647">
            <description>Offset</description>
        </field>
        <field tagRef="9648">
            <description>Offset Units/Direction</description>
        </field>
        <field tagRef="9646">
            <description>Anchor Price</description>
        </field>
        <group ref="StandardMessageTrailer" required="true"/>
    </fieldList>
</message>

Я знаю, как вставить после этой строки, используя

sed 'group ref="StandardMessageTrailer"/r file2.xml' file1.xml > newfile.xml  

но я хочу вставить его раньше.

ценю помощь


sed
person user301200    schedule 25.03.2010    source источник
comment
Я хотел бы увидеть реальное решение sed - я знаю, что это возможно с чем-то вроде /StandardMessageTrailer/{x;r insert;G}, но это не совсем то...   -  person Cascabel    schedule 25.03.2010


Ответы (5)


f2="$(<file2)"
awk -vf2="$f2" '/StandardMessageTrailer/{print f2;print;next}1' file1 

если вы хотите sed, вот один из способов

sed  -e '/StandardMessageTrailer/r file2' -e 'x;$G' file1
person ghostdog74    schedule 25.03.2010
comment
Ваша версия sed не печатает последнюю строку файла file1. Если вы добавите -e '$G' после 'x', то это произойдет, но произойдет сбой, если строка с регулярным выражением является последней строкой в ​​файле1, путем печати этой строки затем содержимого файла2. - person Dennis Williamson; 25.03.2010
comment
@деннис спасибо. в отношении проблемы с регулярным выражением последней строки. Держу пари, что пока этого не произойдет. :) как видите, мое предпочтительное решение не sed. - person ghostdog74; 25.03.2010
comment
В MacOS вы можете записать изменения прямо в файл, добавив -i.bak к команде: sed -i.bak -e '/StandardMessageTrailer/r file2' -e 'x;$G' file1 - person John Dunne; 22.01.2016

Если вы можете сделать два прохода, вы можете использовать маркер:

sed '/Standard/i MARKER' file1.xml | sed -e '/MARKER/r file2.xml' -e '/MARKER/d'

Проблема с попыткой сделать это за один проход заключается в том, что нет другого способа (известного мне), кроме 'r', вставить содержимое файла, а 'r' делает это в выходном потоке вне досягаемости манипуляций. , после того, как sed завершит работу со строкой. Поэтому, если «Стандарт» находится в последней строке, все, что вы с ним делаете, будет завершено к тому времени, когда появится файл2.

person Beta    schedule 25.03.2010

Обычно я делаю так:

  1. file1, файл для чтения содержимого вставки
  2. file2, вставить содержимое для чтения из file1 в начало file2
  3. фрагмент сценария:

    sed "\$r ${file2}" ${file1} > tmpfile
    mv tmpfile ${file2}

person Tong    schedule 18.12.2012

Вот решения, которые сработали для меня:

  1. Использование маркера, подобного объясненному в другом ответе:

    sed '/StandardMessageTrailer/i MARKER' file1.xml | sed -e '/MARKER/r file2.xml' -e '/MARKER/d'
    
  2. Подсчет строки, когда она произошла как объяснено в другом ответе на аналогичный вопрос:

    LINE_NUMBER_MATCHING=$(sed -n '/StandardMessageTrailer/=' file1.xml) && sed "$((${LINE_NUMBER_MATCHING} - 1))r file2.xml" file1.xml
    
  3. Или используя sed как описано в другом ответе на аналогичный вопрос:

    sed $'/StandardMessageTrailer/{e cat file2.xml\n}' file1.xml
    
person Anthony O.    schedule 14.09.2018

Я пробовал разные решения, и одно из бета-тестирования сработало за меня.

Обзор:

  • Я хотел вставить разные файлы в основной файл
  • Я хотел использовать маркеры, чтобы указать, куда я хочу вставить эти файлы.

Пример:
Создайте 2 файла:

cloud_config.yml:

coreos:
__ETCD2__

etcd2.yml :

  etcd2:
    name:                         __HOSTNAME__
    listen-peer-urls:             http://__IP_PUBLIC__:2380
    listen-client-urls:           http://__IP_PUBLIC__:2379,http://127.0.0.1:2379

Затем мы запускаем на нем этот скрипт:

sed '/Standard/i __ETCD2__' cloud_config.yml \
| sed -e "/__ETCD2__/r etcd2.yml" > tmpfile
sed "s|__ETCD2__||g" tmpfile > cloud_config.yml

Наконец-то мы это сделали:

coreos:
  etcd2:
    name:                         __HOSTNAME__
    listen-peer-urls:             http://__IP_PUBLIC__:2380
    listen-client-urls:           http://__IP_PUBLIC__:2379,http://127.0.0.1:2379
person Thibault Deheurles    schedule 13.09.2015