Я часто использую 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 для этой рабочей копии.
find ... -print0 | xargs -0 egrep ...
вместоfind ... -exec grep ...
(неgrep
для каждого файла, но для нескольких файлов одновременно). С помощью этой формы вы также можете обрезать.svn
каталоги, не используя-prune
опцию find, т.е.find ... -print0 | egrep -v '/\.svn' | xargs -0 egrep ...
-exec
with+
не разветвляетсяgrep
для каждого файла, в то время как использование with;
делает. Использование-exec
на самом деле более правильно, чем использованиеxargs
. Обратите внимание, что такие команды какls
что-то делают, даже если список аргументов пуст, в то время как такие командыchmod
дают ошибку, если аргументов недостаточно. Для того, чтобы увидеть , что я имею в виду, просто попробуйте следующую команду в каталоге , который не имеет какой - либо скрипт:find /path/to/dir -name '*.sh' -print0 | xargs -0 chmod 755
. Сравните с этим:find /path/to/dir -name '*.sh' -exec chmod 755 '{}' '+'
.grep
выход.svn
тоже не очень хорошая идея. Покаfind
специализируется на обработке свойств файла,grep
нет. В вашем примере файл с именем '.svn.txt' также будет отфильтрован вашейegrep
командой. Хотя вы можете изменить свое регулярное выражение на «^ / \. Svn $» , это все же не очень хорошая практика.-prune
Предикатfind
отлично работает для фильтрации файлов (по имени файла, или создания временной метки, или независимо от состояния вы прилагается). Это похоже на то, что даже если вы можете убить таракана с помощью большого меча, это не значит, что это рекомендуемый способ сделать это :-).Ответы:
Для поиска могу я предложить вам посмотреть на ack ? Он осведомлен об исходном коде
find
и поэтому автоматически игнорирует многие типы файлов, включая информацию о репозитории исходного кода, такую как приведенная выше.источник
ack
очень нравится , но я обнаружил, что это значительно медленнее, чемfind -type f -name "*.[ch]" | xargs grep
при работе с большой кодовой базой.ack
считается, что лучшеgrep
, не с учетом источникаfind
? Некоторые примеры использования его для заменыfind
сделают это реальным ответом.почему не просто
Предикат -not отменяет все, что имеет .svn в любом месте пути.
Так что в вашем случае это будет
источник
'*.svn*'
сначала, но потом'*.svn'
. Какой правильный? Работают ли оба? Я думаю, что это должно быть'*.svn*'
?Следующим образом:
Или, альтернативно, на основе каталога, а не префикса пути:
источник
find . -type d -name .svn -prune -o -print
потому что это немного быстрее. Согласно стандарту POSIX , выражения оцениваются одно за другим в указанном порядке. Если первое выражение в-a
являетсяfalse
, второе выражение не будет оценено (также называемое коротким замыканием и оценкой ).-type d
перед-name .svn
теоретически более эффективна. Тем не менее, это обычно незначительно, за исключением случаев, когда у вас очень очень большое дерево каталогов.-print
как часть последнего выражения. Нечто подобноеfind . -name .git -prune -o \( -type f -name LICENSE -print \)
работает как положено.find . -name .svn -prune -o -name .git -prune -o -type d -print
. Это может быть на несколько миллисекунд быстрее,-type d
чем раньше-name
, но это не стоит дополнительного набора текста.Для того, чтобы игнорировать
.svn
,.git
и другие скрытые каталоги (начинающиеся с точки), попробуйте:Однако, если целью использования
find
является поиск в файлах, вы можете попробовать использовать эти команды:git grep
- специально разработанная команда для поиска шаблонов в репозитории Git.ripgrep
- который по умолчанию игнорирует скрытые файлы и файлы, указанные в.gitignore
.Связанный: Как мне найти все файлы, содержащие определенный текст в Linux?
источник
Вот что я бы сделал в вашем случае:
rgrep
Встроенная команда Emacs игнорирует.svn
каталог и многие другие файлы, которые вам, вероятно, не нужны при выполненииfind | grep
. Вот что он использует по умолчанию:Он игнорирует каталоги, созданные большинством систем контроля версий, а также созданные файлы для многих языков программирования. Вы можете создать псевдоним , который вызывает эту команду и заменить
find
иgrep
шаблоны для ваших проблем конкретных.источник
GNU найти
источник
-type d
) - этот ответ сделал. +1Я использую grep для этой цели. Поместите это в ваш ~ / .bashrc
grep автоматически использует эти опции при вызове
источник
GREP_OPTIONS=xxx grep "$@"
. Это означает, что переменная GREP_OPTIONS установлена только для экземпляров grep, которые я запускаю вручную, используя 'grp'. Это означает, что у меня никогда не возникает ситуация, когда я запускаю инструмент, и внутренне он вызывает grep, но инструмент запутывается, потому что grep ведет себя не так, как ожидалось. Кроме того, у меня есть вторая функция grpy, которая вызывает grp, но добавляет--include=*.py
, чтобы просто искать файлы Python.grep --exclude=tags --exclude_dir=.git ...etc... "$@"
. Мне нравится, что это работает как «ack», но я сохраняю понимание и контроль над тем, что он делает.find . | grep -v \.svn
источник
.
в.svn
регулярном выражении.| fgrep -v /.svn/
или `| grep -F -v / .svn / `для исключения именно каталога, а не файлов с" .svn "как частью их имени.Почему бы вам не передать команду с помощью grep, который легко понять:
источник
.
в.svn
регулярном выражении.Создайте скрипт с именем
~/bin/svnfind
:Этот скрипт ведет себя идентично простой
find
команде, но он удаляет.svn
каталоги. В остальном поведение идентично.Пример:
источник
echo
к команде find и сказать, какая команда выполняется?svnfind -type f
отлично работает на моей машине Red Hat.echo find "${OPTIONS[@]}"...
так, чтобы она печатала команду поиска вместо фактического ее запуска.echo find ${OPTIONS[@]} ${PATHS[@]} -name .svn -type d -prune -o ( ${EXPR[@]} ) $ACTION
, Это дает мне следующий вывод:find -type f -name .svn -type d -prune -o ( -true ) -print
Просто подумал, что я добавлю простую альтернативу постам Калеба и других (которые подробно описывают использование
find -prune
опцииack
,repofind
команд и т. Д.), Которая особенно применима к использованию, которое вы описали в вопросе (и любым другим подобным использованиям):Для повышения производительности, вы всегда должны пытаться использовать
find ... -exec grep ... +
(спасибо Кэндзи за указание на это) илиfind ... | xargs egrep ...
(переносной) илиfind ... -print0 | xargs -0 egrep ...
(GNU; работы на имена файлов , содержащих пробелы) , а не изfind ... -exec grep ... \;
.Форма
find ... -exec ... +
andfind | xargs
не форкаетсяegrep
для каждого файла, а скорее для нескольких файлов за раз, что приводит к гораздо более быстрому выполнению .При использовании
find | xargs
формы также можно использовать ,grep
чтобы легко и быстро чернослив.svn
(или любые каталоги или регулярное выражение), то естьfind ... -print0 | grep -v '/\.svn' | xargs -0 egrep ...
(полезно , когда вам нужно что - то быстро и не могут быть обеспокоены , чтобы помнить , как настроитьfind
«s-prune
логику.)find | grep | xargs
Подход аналогичен GNUfind
«S-regex
опции (смghostdog74
» s пост), но более компактен (также будет работать на платформах , где GNUfind
не доступен.)источник
-exec
переключения есть две формыfind
: одна заканчивается;
на другую, а другая заканчивается на+
. Один, заканчивающийся на,+
заменяет{}
список всех соответствующих файлов. Кроме того, ваше регулярное выражение также'/\.svn'
соответствует именам файлов'.svn.txt'
. Пожалуйста, обратитесь к моим комментариям к вопросу для получения дополнительной информации.find
утилиты. Пожалуйста, смотрите-exec
часть :-).В репозитории исходного кода я обычно хочу делать вещи только с текстовыми файлами.
Первая строка - это все файлы, кроме файлов репозитория CVS, SVN и GIT.
Вторая строка исключает все двоичные файлы.
источник
Я использую find с опциями -not -path. Мне не повезло с черносливом.
найдет файлы groovy не в пути к целевому каталогу.
источник
Чтобы решить эту проблему, вы можете просто использовать это условие поиска:
Вы можете добавить больше ограничений следующим образом:
Вы можете найти более подробную информацию об этом в справочной странице раздела «Операторы»: http://unixhelp.ed.ac.uk/CGI/man-cgi?find
источник
Обратите внимание, что если вы делаете
find . -type f -name 'messages.*'
тогда
-print
подразумевается, когда все выражение (-type f -name 'messages.*'
) истинно, потому что нет «действия» (например-exec
).Хотя, чтобы прекратить спуск в определенные каталоги, вы должны использовать все, что соответствует этим каталогам, и следовать за ним
-prune
(что предназначено для того, чтобы прекратить спуск в каталоги); вот так:find . -type d -name '.svn' -prune
Это дает значение True для каталогов .svn, и мы можем использовать логическое короткое замыкание, следуя за этим
-o
(OR), после чего то, что следует после,-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
действие подразумевается, но будет применяться к выражению-name '.svn' -prune -o
WHOLE , включая часть, и, таким образом, печатать все каталоги .svn, а также файлы 'message. *', что, вероятно, не то, что вам нужно. Поэтому при использовании-prune
таким способом вы всегда должны использовать «действие» в правой части логического выражения . И когда это действие печатается, вы должны явно добавить его, например, так:find . -name '.svn' -prune -o -name 'message.*' -print
источник
Попробуйте findrepo, который является простой оболочкой для find / grep и намного быстрее, чем ack. В этом случае вы бы использовали его следующим образом:
источник
wcfind
скрипт поиска оболочки, который я использую для автоматического удаления каталогов .svnисточник
Это работает для меня в приглашении Unix
Приведенная выше команда выведет список файлов, которые не относятся к .svn, и выполнит упомянутый вами grep.
источник
xxx.svnxxx
. Это важно - например, если вы используете git вместо svn, вам часто нужно включать файлы, такие как .gitignore (это не метаданные, это обычный файл, который включен в репозиторий) в результаты поиска.я обычно передаю вывод через grep еще раз, удаляя .svn, в моем случае он не намного медленнее. Типичный пример:
ИЛИ
источник
Если вы скажете find для поиска через '*', тогда он пропустит все "точечные файлы" в корне:
или с пути
Это не точное / идеальное решение вопроса. Однако немногие решения проще, чем это. Производительность тоже отличная, поскольку она даже не входит в скрытые каталоги.
недостатки:
Таким образом, в вашем примере добавление звезды - единственная модификация, которая вам понадобится:
источник