Как мне заставить `find` игнорировать каталоги .svn? - PullRequest
218 голосов
/ 23 февраля 2010

Я часто использую команду find для поиска по исходному коду, удаления файлов, чего угодно. Досадно, потому что Subversion хранит дубликаты каждого файла в своих .svn/text-base/ каталогах, и мои простые поиски заканчиваются тем, что они получают много повторяющихся результатов. Например, я хочу рекурсивно искать uint в нескольких messages.h и messages.cpp файлах:

# find -name 'messages.*' -exec grep -Iw uint {} +
./messages.cpp:            Log::verbose << "Discarding out of date message: id " << uint(olderMessage.id)
./messages.cpp:    Log::verbose << "Added to send queue: " << *message << ": id " << uint(preparedMessage->id)
./messages.cpp:                Log::error << "Received message with invalid SHA-1 hash: id " << uint(incomingMessage.id)
./messages.cpp:            Log::verbose << "Received " << *message << ": id " << uint(incomingMessage.id)
./messages.cpp:            Log::verbose << "Sent message: id " << uint(preparedMessage->id)
./messages.cpp:        Log::verbose << "Discarding unsent message: id " << uint(preparedMessage->id)
./messages.cpp:        for (uint i = 0; i < 10 && !_stopThreads; ++i) {
./.svn/text-base/messages.cpp.svn-base:            Log::verbose << "Discarding out of date message: id " << uint(olderMessage.id)
./.svn/text-base/messages.cpp.svn-base:    Log::verbose << "Added to send queue: " << *message << ": id " << uint(preparedMessage->id)
./.svn/text-base/messages.cpp.svn-base:                Log::error << "Received message with invalid SHA-1 hash: id " << uint(incomingMessage.id)
./.svn/text-base/messages.cpp.svn-base:            Log::verbose << "Received " << *message << ": id " << uint(incomingMessage.id)
./.svn/text-base/messages.cpp.svn-base:            Log::verbose << "Sent message: id " << uint(preparedMessage->id)
./.svn/text-base/messages.cpp.svn-base:        Log::verbose << "Discarding unsent message: id " << uint(preparedMessage->id)
./.svn/text-base/messages.cpp.svn-base:        for (uint i = 0; i < 10 && !_stopThreads; ++i) {
./virus/messages.cpp:void VsMessageProcessor::_progress(const string &fileName, uint scanCount)
./virus/messages.cpp:ProgressMessage::ProgressMessage(const string &fileName, uint scanCount)
./virus/messages.h:    void _progress(const std::string &fileName, uint scanCount);
./virus/messages.h:    ProgressMessage(const std::string &fileName, uint scanCount);
./virus/messages.h:    uint        _scanCount;
./virus/.svn/text-base/messages.cpp.svn-base:void VsMessageProcessor::_progress(const string &fileName, uint scanCount)
./virus/.svn/text-base/messages.cpp.svn-base:ProgressMessage::ProgressMessage(const string &fileName, uint scanCount)
./virus/.svn/text-base/messages.h.svn-base:    void _progress(const std::string &fileName, uint scanCount);
./virus/.svn/text-base/messages.h.svn-base:    ProgressMessage(const std::string &fileName, uint scanCount);
./virus/.svn/text-base/messages.h.svn-base:    uint        _scanCount;

Как я могу сказать find игнорировать каталоги .svn?


Обновление : если вы обновите свой SVN-клиент до версии 1.7 , это больше не проблема.

Ключевой особенностью изменений, внесенных в Subversion 1.7, является централизация хранилища метаданных рабочей копии в одном месте. Вместо каталога .svn в каждом каталоге рабочей копии в рабочих копиях Subversion 1.7 есть только один каталог .svn - в корне рабочей копии. Этот каталог включает (среди прочего) базу данных на основе SQLite, которая содержит все метаданные, необходимые Subversion для этой рабочей копии.

Ответы [ 19 ]

5 голосов
/ 08 марта 2010

Просто подумал, что добавлю простую альтернативу к сообщениям Калеба и других (в которых подробно описано использование опции find -prune, ack, repofind и т. Д.), Которая особенно применимо к использованию, которое вы описали в вопросе (и любым другим подобным использованиям):

  1. Для производительности вы всегда должны пытаться использовать find ... -exec grep ... + (спасибо Кенджи за указание на это) или find ... | xargs egrep ... (переносимый) или find ... -print0 | xargs -0 egrep ... (GNU; работает с именами файлов, содержащими пробелы) из find ... -exec grep ... \;.

    Форма find ... -exec ... + и find | xargs формирует не egrep для каждого файла, а скорее для нескольких файлов за раз, что приводит к гораздо более быстрому выполнению .

  2. При использовании формы find | xargs вы также можете использовать grep для простого и быстрого сокращения .svn (или любых каталогов или регулярных выражений), то есть find ... -print0 | grep -v '/\.svn' | xargs -0 egrep ... (полезно, когда вам нужно что-то быстрое и Не забудьте вспомнить, как настроить find -prune логика.)

    Подход find | grep | xargs аналогичен опции -regex GNU find (см. Пост ghostdog74), но более переносим (также будет работать на платформах, где GNU find недоступна. )

4 голосов
/ 07 марта 2014

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

Первая строка - это все файлы, кроме файлов репозитория CVS, SVN и GIT.

Вторая строка исключает все двоичные файлы.

find . -not \( -name .svn -prune -o -name .git -prune -o -name CVS -prune \) -type f -print0 | \
xargs -0 file -n | grep -v binary | cut -d ":" -f1
3 голосов
/ 13 июня 2014

Я использую поиск с опциями -not -path. Мне не повезло с черносливом.

find .  -name "*.groovy" -not -path "./target/*" -print

найдет файлы groovy не по пути к целевому каталогу.

2 голосов
/ 27 декабря 2016

Обратите внимание, что если вы делаете

find . -type f -name 'messages.*'

затем -print подразумевается, когда все выражение (-type f -name 'messages.*') истинно, потому что нет «действия» (например, -exec).

Хотя, чтобы прекратить спуск в определенные каталоги, вы должны использовать все, что соответствует этим каталогам, и следовать за ним -prune (что предназначено для того, чтобы прекратить спуск в каталоги); вот так:

find . -type d -name '.svn' -prune

Это оценивается как True для каталогов .svn, и мы можем использовать логическое короткое замыкание, следуя этому по -o (ИЛИ), после чего то, что следует после проверки -o, проверяется только когда первая часть имеет значение False, следовательно, не каталог .svn. Другими словами, следующее:

find . -type d -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}

будет оценивать только то, что справа от -o, а именно -name 'message.*' -exec grep -Iw uint {}, для файлов, НЕ находящихся внутри каталогов .svn.

Обратите внимание, что, поскольку .svn, скорее всего, всегда является каталогом (а не, например, файлом), и в этом случае, безусловно, не соответствует названию 'message. *', Вы могли бы также пропустить -type d и сделать:

find . -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}

Наконец, обратите внимание, что если вы пропустите какое-либо действие (-exec - это действие), произнесите так:

find . -name '.svn' -prune -o -name 'message.*'

тогда подразумевается действие -print, но оно будет применяться к выражению WHOLE, включая часть -name '.svn' -prune -o, и, таким образом, печатать все каталоги .svn, а также файлы 'message. *', Что, вероятно, не то, что вам нужно , Поэтому при использовании -prune таким образом вы всегда должны использовать «действие» в правой части логического выражения. И когда это действие печатается, вы должны явно добавить его, например, так:

find . -name '.svn' -prune -o -name 'message.*' -print

2 голосов
/ 23 февраля 2010

Try findrepo , который является простой оболочкой для find / grep и намного быстрее, чем ack Вы бы использовали его в этом случае как:

findrepo uint 'messages.*'
2 голосов
/ 17 сентября 2014

Чтобы решить эту проблему, вы можете просто использовать это условие поиска:

find \( -name 'messages.*' ! -path "*/.svn/*" \) -exec grep -Iw uint {} +

Вы можете добавить больше ограничений следующим образом:

find \( -name 'messages.*' ! -path "*/.svn/*" ! -path "*/CVS/*" \) -exec grep -Iw uint {} +

Подробнее об этом вы можете узнать в справочной странице раздела «Операторы»: http://unixhelp.ed.ac.uk/CGI/man-cgi?find

2 голосов
/ 08 марта 2010

wcfind - это скрипт поиска оболочки, который я использую для автоматического удаления каталогов .svn.

1 голос
/ 19 марта 2013

Я обычно передаю вывод через grep еще раз, удаляя .svn, в моем случае он не намного медленнее. Типичный пример:

find -name 'messages.*' -exec grep -Iw uint {} + | grep -Ev '.svn|.git|.anythingElseIwannaIgnore'

OR

find . -type f -print0 | xargs -0 egrep messages. | grep -Ev '.svn|.git|.anythingElseIwannaIgnore'
1 голос
/ 09 января 2012

Это работает для меня в приглашении Unix

gfind.\ (-not -wholename '* \. svn *' \) -type f -name 'messages. *' -exec grep -Iw uint {} +

Приведенная выше команда выведет список файлов, которыене с .svn и делайте упомянутый вами grep.

...