2016-01-29 3 views
2

У меня есть файл XML со следующей структурой:Заменить каждую строку с другим текстом с помощью «SED» (скрипт)

<root> 
     <station name = "insert_text"/> 
     <station name = "insert_text"/> 
     <station name = "insert_text"/> 
    </root> 

Я хотел, чтобы заменить текст «insert_text» со значениями из текстового файла который выглядит следующим образом:

Station1 
    Station2 
    Station3 

После прочтения входного файла выше, сгенерированный файл XML должен выглядеть следующим образом:

<root> 
     <station name = "Station1"/> 
     <station name = "Station2"/> 
     <station name = "Station3"/> 
    </root> 

Используемый мной сценарий выглядит следующим образом, и он заменяет все 3 строки только «Station1».

while read a 
    do 
     sed -i -e "s/insert_text/$a/g" filename.xml 
    done<inputfile.txt 

Что я должен изменить, чтобы заменить каждую из строк в XML-файле разными текстами?

+1

Каждый раз, когда вы пишете цикл в оболочке, чтобы манипулировать текст, который вы имеете неправильный подход. См. Например http://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text-considered-bad-practice. Это работа для awk. –

ответ

3

Проблема

Проблема с кодом является то, что когда-то он заменяет insert_text в файле, более insert_text s заменить на Station2 и Station3.

Решение

Решение бросить замещающий когда первый insert_text уже заменить, и прочитать следующую строку из файла

Вы можете сделать это

while read a;  
do   
    sed "1,/insert_text/ s/insert_text/$a/; " input;  
done < file 

Что он делает?

  • 1,/insert_text/ Это диапазон адресов, рассказывает СЭД, чтобы сделать замену от линии 1 до первого insert_text. Никакие другие insert_text s не будут заменены

ИЛИ

sed "/insert_text/{s/insert_text/$a/;q;}" input; 
+0

Хороший подход, но я бы это реализовал с помощью 'sed '/ insert_text/{s // $ a/g; q;}" ' –

+0

@WilliamPursell Да, это должно работать в gnu-sed, я тестировал в BSD sed и не смог заставить его работать. – nu11p01n73R

+0

Помимо бессмысленного использования 'g', то, что @WilliamPursell предлагает _does_ работать с BSD Sed. Как правило, вызов Sed в цикле будет очень медленным для любых других, кроме небольших файлов. – mklement0

3

Я думаю awk лучше подходит для этой задачи:

Демо

$ cat inputfile.dat 
Station1 
Station2 
Station3 
$ cat filename.xml 
    <root> 
     <station name = "insert_text"/> 
     <station name = "insert_text"/> 
     <station name = "insert_text"/> 
    </root> 


$ awk 'NR==FNR{a[++c]=$1;next}/station name/{sub("insert_text",a[++i])}1' inputfile.dat filename.xml 
    <root> 
     <station name = "Station1"/> 
     <station name = "Station2"/> 
     <station name = "Station3"/> 
    </root> 
1

Другой AWK взять на это ... Вместо того, чтобы читать один файл в массив в памяти, а затем читает второй файл для текста, заменить, вы можете передавать через оба файла сразу:

$ cat inp1 
Station1 
Station2 
Station3 
$ cat inp2 
    <root> 
     <station name = "insert_text"/> 
     <station name = "insert_text"/> 
     <station name = "insert_text"/> 
    </root> 
$ awk -vtext="insert_text" '$0~text{getline stn <"inp1"; sub(/insert_text/,stn)} 1' inp2 
    <root> 
     <station name = "Station1"/> 
     <station name = "Station2"/> 
     <station name = "Station3"/> 
    </root> 

Такой подход будет выгодным, если ваш список станций больше, чем вы можете умещаться в м Эмори.

Разразившийся для более легкого чтения, вот что делает скрипт:

$0 ~ text {     # run these commands if we find your text 
    getline stn <"inp1"  # read a new input line from the file "inp1" 
    sub(/insert_text/,stn) # do the substitution. 
} 
1       # shorthand for "print the current line". 
Смежные вопросы