Присвойте элементы Array сопоставленному шаблону по порядку. - PullRequest
0 голосов
/ 29 января 2019

У меня есть xml с похожими блоками по всему файлу:

<name> test </name>
<marker>
<name> test </name>

<xyz> some txt </xyz>
<abc> something </abc>

<name>test</name>
<marker>
<name>test</name>

Теперь я хочу найти «маркер» и заменить строку выше и ниже первого маркера на test1, 2-го маркера на test2 итак что

я попробовал:

array=( test1, test2); 
for ((i=0;i<${#array[@]};i++)); do;
sed -i '/<marker>/!b;n;c<name>'`echo ${array[$i]}`'<\/name>' filename;
done

Проблема здесь в следующем: он всегда заменяет все значения на test2.но я хочу последовательную замену, поскольку 1-й маркер должен иметь test1 выше и ниже, 2-й маркер должен иметь test2 выше и ниже и т. д.

Ответы [ 3 ]

0 голосов
/ 29 января 2019

Вот что вы можете сделать.Операции ограничены диапазоном 1, / marker /, а маркер заменяется другим словом, чтобы избежать второго совпадения.Последнее значение sed в конце восстанавливает все значения маркера.

Для упрощения замена выполняется строкой многострочной замены с кавычками '\ n'.

array=( test1 test2);
marker='<marker>'
processed='<markerprocessed>' # or whatever cannot happen in input
for ((i=0;i<${#array[@]};i++)); do
    replace='<name>'${array[$i]}'<\/name>\n'${processed}'\n<name>'${array[$i]}'<\/name>' # edit as required
    sed -i  -e '1,/${marker}/'s/${marker}/${replace}/  $file
done
sed -i s/${processed}/${marker}/ $file

0 голосов
/ 30 января 2019

Это может сработать для вас (GNU sed):

sed -r '1{x;s/^/1/;x};N;/\n<marker>/!{P;D};N;G;s/.*(\n.*\n).*\n(.*)/<name>test\2<\/name>\1<name>test\2<\/name>/;x;s/.*/expr & + 1/e;x' file

В начале файла заполняется счетчик 1. Счетчик удерживается в области удержания и увеличивается после каждой замены.

Создайте окно из двух строк по всей длине файла.Если вторая строка в окне не начинается <marker>, выведите первую строку, а затем удалите ее и повторите.В противном случае добавьте третью строку, а затем добавьте счетчик из области удержания.Используя сопоставление с образцом, замените первую и третью строки требуемым тестом.

Наконец увеличьте счетчик, готовый к следующему совпадению, и выведите последние три строки, которые были изменены.

0 голосов
/ 29 января 2019

Ну, я не нашел простого способа сделать это с одной строкой, но простой скрипт мог бы сделать это:

matchcount=`grep '<marker>' -c test-input.txt`
i=1
while [[ $i -le $matchcount ]]
do
  line=`grep '<marker>' -m 1 -n test-input.txt | grep -o '^[0-9*]'`
  nextline=$((line+1))
  prevline=$((line-1))
  cmd1=`echo $prevline`'s/.*/<name>test'`echo $i`'<\/name>/'
  cmd2=`echo $line`'s/.*/REPLACED/'
  cmd3=`echo $nextline`'s/.*/<name>test'`echo $i`'<\/name>/'
  sed -i $cmd1 test-input.txt
  sed -i $cmd2 test-input.txt
  sed -i $cmd3 test-input.txt
  ((i = i + 1))
done
sed -i 's/REPLACED/<marker>/' test-input.txt

Объяснение:

  • Повторяйте столько раз, сколько <marker> появляется в файле
  • Найдите первое вхождение <marker> с помощью grep, сохраните его номер строки и окружающие.
  • Для каждой строки используйте разныеКоманда sed: замените имя или замените вхождение маркера, чтобы оно не совпадало снова.
  • Замените все ЗАМЕНЕННЫЕ обратно, как только это будет сделано

Я уверен, что это можно сделать за меньшее количестволинии, но это сделано, чтобы быть простым для чтения.Вы можете улучшить его, если хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...