Архив рубрики «find»

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

09.02.2009

Задача: найти все файлы содержащие 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

vim tabs

01.10.2008

Открыть сразу несколько файлов в tab'ах в vim можно так:

~$ vim -p `find -type f -name '*.rb' -print0 | xargs -0 file -i | grep -v 'utf-8' | awk '{print $1}' | sed 's/://'`

(пример от Харитона, открываем в vim все ruby-файлы в кодировке, отличной от utf-8)
Здесь важен ключ -p: открыть файлы в табах.

Vim откроет столько буферов, сколько нашлось файлов, но не более tabpagemax, по умолчанию 10. Изменить количество табов можно в ~/.vimrc так:

set tabpagemax=15

При превышении tabpagemax новые табы не создаются, но навигировать по файлам все равно можно командами :next и :last.

Переключаться между табами можно командами: :tabnext, :tabprevious, :tablast, :tabfirst. Можно замапить из на горячие клавиши. Можно пользоваться горячими клавишами <C-PgUp> and <C-PgDown>.

Ещё полезное:
:tabn[ew] - открыть новый таб
:tabe[dit] [++opt] [+cmd] {file} - открыть файл в новом табе (типа :edit)
:tabf[ind] [++opt] [+cmd] {file} - найти файл в path и открыть в новом табе (типа :find)
CTRL-W gf - редактировать файл с именем, находящимся под курсором, в новом табе
CTRL-W gF - редактировать файл с именем, находящимся под курсором, в новом табе. Отмотать на строку которая указана после имени файла
:tabc[lose][!] - закрыть таб
:tabo[nly][!] - закрыть все табы кроме активного
:tabn[ext] (gt, <C-PageDown>) - переключиться на следующий таб
:tabp[revious] (:tabN[ext], gT) - на предыдущий таб
:tabr[ewind] (:tabfir[st]) - на первый таб
:tabl[ast] - на последний
:tabs - список табов
:tabm[ove] [N] - переместить текущий таб на место сразу за N-ым
:tabd[o] {cmd} - выполнить команду на каждом из табов (:tabdo %s/foo/bar/g)

Подробнее здесь - :help tabpage

Еще интересная фишка. Если переместить курсор на имя файла и нажать gf (go-to-file), то откроется альтернативный буфер с содержимым указанного файла. Старый файл как-бы пропадет из поля зрения. Однако на него можно быстро переключиться командой C-^, так же и обратно. Так удобно редактировать 2 файла одновременно.

По поводу полезных маппингов:
http://www.bygonesky.com/Programming/Settings/Vim/carlos.vim.html, смотреть начиная со 125-й строки.

Переименовать все файлы в нижний регистр

07.09.2008

Переименовать все файлы в текущей и во всех вложенных директориях в нижний регистр:

~$ find ./ -type f | awk '{ print $1 " " tolower($1) }' | xargs -L 1 mv

Харитон Мизгирь пишет: Чтобы обрабатывались пути с пробелами и проч. непечатностями надо использовать конструкцию типа:
~$ find -print0 | xargs -0

Объяснение по поводу параметра -print0 (find'а) и -0 (xargs'а)

В имени файла может попасться символ, который требует экранирования при обработке (single or double quotes, spaces or newlines). print0 заставляет выводить список найденных файлов разделяя их через нуль-символ ('\0', в духе языка C, где он используется для декларации конца строки). xargs тоже должен быть готов к такому разделителю, для этого служит -0.

find и xargs по разному себя ведет когда ищут из текущей директории или когда ищут из родительской (в родительской прекрасно обрабатывал директории с пробелами и любыми кавычками, которые находились в дочерней директории). newlines не обрабатывается нигде.

Провел такой эксперимент. Создал скрипт (в файле):

mkdir "Bad \
bad \
bad \
dir"

– получил директорию с newlines.

Создал там файл README.txt и попытался его найти:

touch README.txt
cd ..
find . -name README.txt | xargs -I % ls %

Получил ошибку:

xargs: unmatched одинарная quote; by default quotes are special to xargs unless you use the -0 option
(загадочное сообщение: "по умолчанию кавычки обрабатываются xargs, если только вы не используете параметр -0")

Та же команда в связке print0-0 работает нормально:

find . -name README.txt -print0 | xargs -0 -I % ls %

Ошибки, которые возникали в текущей директории (в родительской все было нормально):

ls: ./Временнаяnдиректория/README.txt: No such file or directory

То есть использование связки print0 ... -0 желательно всегда. Можно прописать через alias'ы.