Назад | Перейти на главную страницу

Bash-скрипт для замены файла, если он имеет определенную строку

У меня есть список файлов, в которых я хочу проверить определенную строку. Если строка существует в файле, я хочу заменить ее новой версией, которая у меня есть. Как проще всего это сделать?

for file in "`grep -l "foo" bar gazi`"; do cp -p --backup=numbered replace "$file"; done

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

Если вам требуется дополнительная помощь в формулировании подходящего регулярного выражения для grep (см. Выше), не стесняйтесь спрашивать.

grep может искать в файле строку и вернет 0, если найдет его, вы можете использовать это как часть условного выражения для замены файла, например:

 #!/bin/bash
 if [ !`/bin/grep -q teststring /path/to/file` ]; then
    cp newfile oldfile
 fi

Предположительно у вас есть файл со списком файлов в нем? Я не знаю, есть ли у вас статический файл, которым вы заменяете совпадающие файлы, или потенциальную замену для каждого файла. Это обрабатывает второй случай, поскольку в первом просто заменяет $ i.new статическим именем файла.

for i in `cat /var/tmp/listoffiles` ; do
    if grep string $i > /dev/null 2>&1 ; then
        cp $i $i.old
        cp $i.new $i
    fi
done

Хотя я согласен со всеми тестами grep, sed действительно может сделать это без теста.

sed -i.BACKUP 's / STRING, ВЫ ХОТИТЕ ЗАМЕНИТЬ / NEW STRING /' файл

Если строки нет, она ничего не сделает. Стоит упомянуть. Из вашего вопроса я не был уверен, пытались ли вы заменить весь файл или только строку в нем.

Правильный способ обработки файлов в цикле в сценарии оболочки - передать команду по конвейеру while или перенаправить файл в done заявление while петля. Это обработает любое имя, кроме тех, которые содержат символы новой строки. Вы не должны использовать форму for f in $(cmd).

В этом примере find это команда, которая создает список файлов:

find . -type f -name "*.txt" | while read -r filename
do
    if grep -qs "$string" "$filename"  # or use >/dev/null 2>&1 instead of -qs
    then
        cp "$replacement" "$filename"
    fi
done

или, здесь список содержится в файле:

while read -r filename
...
done < "$file_with_list"

Другой метод - использовать xargs.

Для команды, которая создает список файлов (например, find):

find . -type f -name "*.txt" -print0 | xargs -0 -I % env string=$string sh 'grep -qs "$string" "%" && cp replacement_file "%"'

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

Если список находится в файле:

xargs -a "$file_with_list" -I % env string=$string sh 'grep -qs "$string" "%" && cp replacement "%"'

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