У меня есть список файлов и соответствующих номеров строк, в которых я хочу выполнить замену:
s/LOG.error/LOG.warn
Есть и другие места, где это может произойти, и я не хочу нарушать эти строки. Как это сделать с помощью find и sed?
Файл имеет следующий формат:
FooBar.java 125
FooBar.java 180
FooBar2.java 128
Вот что я нашел, когда искал способ это сделать:
cat filenames.txt | xargs sed -i '<get-line-number-here>s/LOG.error/LOG.warn' <get-file-name-here>
решение1
Вам нужно будет разбить файл на разделы по файлу назначения и выполнить sed -i
для каждого файла по отдельности. Предполагая, что у вас есть имена файлов и номера строк, сгруппированные по имени файла и в порядке возрастания, вы можете сделать что-то вроде
awk '$1 != prev { if (prev) print "\047 " prev;
prev=$1;
printf "sed -i \047" }
{ print $2 "s/LOG\\.error/LOG.warn/" }
END { if (prev) print "\047 " prev }' filenames.txt | sh
Это быстрый и грязный хак, который может привести к интересным и, возможно, опасным нарушениям, если имена файлов в первом столбце не являются одним токеном.
Мы по сути рефакторим ваш текстовый файл в последовательность sed
скриптов. Таким образом, ваш пример будет превращен в
sed -i '125s/LOG\.error/LOG.warn
180s/LOG\.error/LOG.warn/
' FooBar.java
sed -i '128s/LOG\.error/LOG.warn/
' FooBar2.java
который, как вы заметите, представляет собой sh
скрипт, содержащий по одному sed
скрипту для каждого файла.
Если вы работаете на платформе *BSD (включая Mac OS), вам нужно будет изменить значение sed -i
на sed -i ''
which в Awk, "sed -i \047\047"
чтобы правильно вставлять одинарные кавычки, не нарушая окружающие кавычки оболочки (чтобы вся строка стала printf "sed -i \047\047 \047" }
(sic)).