Как я могу вставить содержимое файла в другой файл прямо перед конкретной строкой - PullRequest
19 голосов
/ 25 марта 2010

Как я могу вставить содержимое файла в другой файл прямо перед определенной строкой, используя 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  

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

благодарю за помощь

Ответы [ 5 ]

20 голосов
/ 25 марта 2010
f2="$(<file2)"
awk -vf2="$f2" '/StandardMessageTrailer/{print f2;print;next}1' file1 

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

sed  -e '/StandardMessageTrailer/r file2' -e 'x;$G' file1
4 голосов
/ 25 марта 2010

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

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

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

1 голос
/ 18 декабря 2012

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

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

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

0 голосов
/ 14 сентября 2018

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

  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
    
0 голосов
/ 13 сентября 2015

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

Резюме:

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

Пример:
Создать 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
...