Поиск и замена в цикле Bash while с использованием sed

Поиск и замена в цикле Bash while с использованием sed

У меня возникла проблема с моим следующим скриптом (это его соответствующая часть):

#!/bin/bash

OLD=(
"_MAIN1_"
"_MAIN2_"
)

NEW=(
"#111"
"#222"
)

length=${#OLD[*]}

i=0

while (( i < length ))
do
  sed -e "s/${OLD[$i]}/${NEW[$i]}/g" oldfile.txt > newfile.txt

  #sed -e 's/_MAIN1_/#111/g' oldfile.txt > newfile.txt  # this works

  # Another way that does not work
  #sed -e 's/'"${OLD[$i]}"'/'"${NEW[$i]}"'/g' oldfile.txt > newfile.txt

  ((i++))
done

exit 0

Моя цель — заменить строки в файле и сохранить его в новый. «Старые» и «новые» строки хранятся в массиве.

Я пробовал много вещей и игрался с одинарными и двойными кавычками - но ничего не работало. Когда я echoпеременные, я получаю правильные строки внутри цикла. Если явно две строки заданы в sedкоманде, это работает нормально.

Шаблоны строк соответствуют шаблонам в моих примерах массивов («new» содержит подчеркивание «_», а «old» содержит хэштег «#»).

Я запускаю bash на компьютере с Ubuntu 16.04.

Большое спасибо!

решение1

Создайте sedскрипт, который выполнит все замены, а затем примените этот sedскрипт к своему файлу.

for (( i=0; i<${#OLD[@]}; ++i )); do
        printf 's/%s/%s/g\n' "${OLD[$i]}" "${NEW[$i]}"
done >script.sed

sed -f script.sed inputfile >outputfile && mv outptufile inputfile && rm script.sed

Таким образом, вы ограничиваете количество раз, которое вам необходимо будет анализировать входной файл, одним.

Для заданных данных в OLDи NEWскрипт sedбудет сгенерирован как

s/_MAIN1_/#111/g
s/_MAIN2_/#222/g

решение2

Весь ваш скрипт (который не работает) можно заменить одной строкой:

sed 's/_MAIN\([12]\)_/#\1\1\1/g' oldfile.txt > newfile.txt

Или, более читабельно, но эквивалентно:

sed 's/_MAIN1_/#111/g;s/_MAIN2_/#222/g' oldfile.txt > newfile.txt

Есть несколько десятков других способов сделать это, в зависимости от вашегодействительныйвариант использования (например, откуда берутся данные, как на самом деле выглядят значения, что вы пытаетесь сделать с данными и т. д.).

решение3

БлагодаряРакеш Шармакомментарий Я мог бы решить эту проблему, используя -iфлаг в команде sed. Перед циклом исходный файл резервируется:

cp oldfile.txt oldfile.backup
while (( i < length ))
do
  sed -i -e 's/'"${OLD[$i]}"'/'"${NEW[$i]}"'/g' oldfile.txt
  ((i++))
done

В следующий раз я буду использовать Perl для работы со строками.

Редактировать:Добавлено ((i++))для предотвращения бесконечного цикла (СпасибоКусаланандакомментарий).

Связанный контент