Unix: Поиск и замена во многих файлах одновременно

Задача: найти все файлы содержащие OLDTEXT, и заменить OLDTEXT на NEWTEXT.

UPD2:Решение, предложенное ocehb:

  1. grep -rl OLDTEXT . | grep -Ev '(~|.o|.a)$' | grep -Ev '/.svn/' | xargs perl -i -pe "s/OLD_TEXT/NEW_TEXT/g;"

UPD1:Вариант без vim:

  1. grep -HR OLDTEXT ./ | awk '{print $1}' | sed 's/:.*$//' | grep -v '~' | sort | uniq | xargs perl -i -pe "s/OLD_TEXT/NEW_TEXT/g;"

Изначально предложенное решение с vim:

  1. grep -HR OLDTEXT ./ | awk '{print $1}' | sed 's/:.*$//' | grep -v '~' | sort | uniq | xargs vim -p

В открывшемся окне vim командуем:

  1. :tabdo %s/OLDTEXT/NEWTEXT/g

(заменить OLDTEXT на NEWTEXT во всех вкладках)

  1. :xa

(записать изменения во всех вкладках)
либо

  1. :qa!

(отменить изменения во всех вкладках)

Ссылки по теме:

  1. VIM FAQ
  2. Save all open buffers at once
  3. Сохранение файла без прав на запись в vim используя sudo
  4. [SLUG] Vim. Search and replace in multiple files

Комментарии (6) на “Unix: Поиск и замена во многих файлах одновременно”

  1. это можно сделать и без вима…

    #!/bin/sh -e
    for fname in `find . -name «*» -print`;do; sed ‘s/OLDTEXT/NEWTEXT/g’ $fname > $fname.new && mv $fname.new $fname; done

  2. Alex Shatlovsky:

    shulc: Да, можно и так. Спасибо за дополнение.

  3. С помощью perl будет намного короче:
    perl -i -pe ‘s/OLD_TEXT/NEW_TEXT/;’ FILE_PATTERN.txt

    например:
    perl -i -pe ‘s/RSS/ATOM/;’ *.html
    заменит во всех html файлах подстроку «RSS» на «ATOM».

  4. Alex Shatlovsky:

    @ehles:

    Согласен, так короче. Но:

    1) Нужен модификатор /g для глобальный замены, а не только первого найденного в каждой строке фрагмента, т.е.

    $ perl -i -pe ’s/OLD_TEXT/NEW_TEXT/g;’ FILE_PATTERN.txt

    2) glob’ы не рулят :) Лучше использовать find:

    $ find ./ -type f -name «*.html» -exec perl -i -pe «s/OLD_TEXT/NEW_TEXT/g;» {} \;

    3) Чтобы не модифицировать файлы без искомой подстроки, можно-таки предварительно отобрать нужные:

    grep -HR OLDTEXT ./ | awk ‘{print $1}’ | sed ‘s/:.*$//’ | grep -v ‘~’ | sort | uniq | xargs perl -i -pe «s/OLD_TEXT/NEW_TEXT/g;»

  5. Dagrus:

    Так короче наверное )

    find . -name ‘*.txt’ -exec grep -ilH «OLD» {} ; | xargs sed -i -e «s/OLD/NEW/g»

  6. По-моему, более vim-овский способ такой.

    Имеем: много файлов *.html, лежащих в одной папке.
    Надо: поменять OLD на NEW во всех файлах.

    :args ../*.html
    :argdo %s/OLD/NEW/ge | update

    Вот и всё.

    В моём случае OLD представляло собой очень большую многострочную конструкцию, и я был чрезвычайно рад, когда нашёл способ сообщить о ней vim-у:

    :argdo %s/OLD-begin\_.*OLD-end/\[email protected]/ge | update

    OLD-begin — начало заменяемого фрагмента, OLD-end — окончание заменяемого фрагмента, причём неважно, сколько и какого текста между ними, конструкция \_.* допускает между ними возвраты каретки.

    \[email protected] здесь написано вместо NEW, потому как вставляемая конструкция тоже была многострочной и просто была скопирована в регистр ‘n’.

Оставить комментарий