Найти и заменить каждый экземпляр одной строки другим из списка или файла - PullRequest
2 голосов
/ 04 апреля 2020

У меня большой XML файл с несколькими экземплярами строки REPLACEME. Во втором файле у меня есть список строк (которые содержат запятые), таких как:

58,-21,0
234,-38,0

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

Я посмотрел на bash (sed, awk, perl) и Powershell. Мне сказали, что я не должен использовать циклы, но использовать циклы файлов и анализировать файл обратно. Поэтому я попробовал это:

file2=/file2.txt
while IFS= read -r line; do
  printf '%s\n' "$line"
  sed '0,/REPLACEME/s//$line/' /file1.xml
done < "$file2"

Но это ничего не делает. Возможно, потому что файлы XML имеют символы? Это не ошибка, это просто ничего не делает.

Рад полностью отказаться от моего кода или переключить парсеры, если я могу найти что-то, что может достичь результата замены?

РЕДАКТИРОВАТЬ: Задано для примера XML. Разметка XML является частью файла KML, строки являются координатными точками. Пример ниже:

<Placemark>
    <name>5005</name>
        <MultiGeometry>
            <Polygon>
                -snip-
            </Polygon>
            <Point>
            <gx:drawOrder>1</gx:drawOrder>
                <coordinates>REPLACEME</coordinates>
            </Point>
        </MultiGeometry>
</Placemark>

В этом файле сотни таких записей, которые необходимо заполнить, используя соответствующие координаты из списка в файле 2.

Ответы [ 2 ]

2 голосов
/ 04 апреля 2020

Используя комбинацию sed и ed - sed создает ed команды из вашего file2.txt:

(sed 's|.*|/REPLACEME/s/REPLACEME/&/|' file2.txt; echo '1,$p') | ed -s file1.xml

Первые REPLACEME в файле XML заменяется первой строкой file2.txt, второй - второй и т. д.

Если вы хотите сохранить изменения в файле, а не просто p , переписав их стандартный вывод, замените echo '1,$p' на echo w.

Если в file2.txt больше строк, чем в REPLACEME, то в file1.xml, ed выведет знак вопроса для каждого на стандартная ошибка. Если вы не хотите их видеть, перенаправьте на /dev/null:

$ (sed 's|.*|/REPLACEME/s/REPLACEME/&/|' file2.txt; echo '1,$p') | ed -s file1.xml 2>/dev/null
<Placemark>
    <name>5005</name>
        <MultiGeometry>
            <Polygon>
                -snip-
            </Polygon>
            <Point>
            <gx:drawOrder>1</gx:drawOrder>
                <coordinates>58,-21,0</coordinates>
            </Point>
        </MultiGeometry>
</Placemark>

Если бы не 2>/dev/null, ваши файлы примеров также дали бы один ?, поскольку file2.txt имеет два в файле XML есть только одна ЗАМЕНА.

2 голосов
/ 04 апреля 2020

Похоже, все, что вам нужно, это:

awk 'NR==FNR{a[NR]=$0; next} /REPLACEME/{sub(/REPLACEME/,a[++c])} 1' file2.txt file1.xml

Обычный совет - использовать инструмент XML, например xmlstarlet или xmllint, при работе с файлами xml, но я лично не знаю ни того, ни другого. достаточно хорошо, чтобы решить эту проблему с ними, и ИМХО это не нужно для того, что вы делаете, предполагая, что REPLACEME происходит только в контексте, показанном в вашем примере.

При манипулировании текстом лучший совет не является " не используйте для циклов "это" не используйте shell циклов ", поэтому использование в то время как l oop также является плохим подходом. См. почему используется оболочка-l oop -процесс-текст-считается-плохой практикой .

Когда вы делаете что-то кроме простого манипулирования текстом (например, чтение списка URL-адресов из файла для запуска curl), тогда можно использовать оболочку l oop и в этом случае (но вместо этого также рассмотреть xargs), а затем да, вам следует избегать for, см. https://mywiki.wooledge.org/DontReadLinesWithFor.

Ваш скрипт sed sed '0,/REPLACEME/s//$line/' не позволит $line расширяться, поскольку он заключен в одинарные кавычки.

...