Ответ 1
Для поиска я могу предложить вам посмотреть ack? Это код исходного кода find
, и как таковой автоматически игнорирует многие типы файлов, включая информацию о репозитории исходного кода, такую как приведенная выше.
Я часто использую команду 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 для метаданных для этой рабочей копии.
Для поиска я могу предложить вам посмотреть ack? Это код исходного кода find
, и как таковой автоматически игнорирует многие типы файлов, включая информацию о репозитории исходного кода, такую как приведенная выше.
почему не просто
find . -not -iwholename '*.svn*'
Не предикат отрицает все, что имеет .svn в любом месте пути.
Итак, в вашем случае это будет
find -not -iwholename '*.svn' -name 'messages.*' -exec grep -Iw uint {} + \;
Как следует:
find . -path '*/.svn*' -prune -o -print
Или, альтернативно, на основе каталога, а не префикса пути:
find . -name .svn -a -type d -prune -o -print
Чтобы игнорировать .svn
, .git
и другие скрытые каталоги (начиная с точки), попробуйте:
find . -type f -not -path '*/\.*'
Однако, если цель использования find
выполняется в файлах, вы можете попробовать использовать следующие команды:
git grep
- специально разработанная команда для поиска шаблонов в репозитории Git.ripgrep
- который по умолчанию игнорирует скрытые файлы и файлы, указанные в .gitignore
.Связано: Как найти все файлы, содержащие определенный текст в Linux?
Вот что я сделал бы в вашем случае:
find . -path .svn -prune -o -name messages.* -exec grep -Iw uint {} +
Встроенная команда Emacs rgrep
игнорирует каталог .svn
и многие другие файлы, которые вам, вероятно, не интересуют при выполнении find | grep
. Вот что он использует по умолчанию:
find . \( -path \*/SCCS -o -path \*/RCS -o -path \*/CVS -o -path \*/MCVS \
-o -path \*/.svn -o -path \*/.git -o -path \*/.hg -o -path \*/.bzr \
-o -path \*/_MTN -o -path \*/_darcs -o -path \*/\{arch\} \) \
-prune -o \
\( -name .\#\* -o -name \*.o -o -name \*\~ -o -name \*.bin -o -name \*.lbin \
-o -name \*.so -o -name \*.a -o -name \*.ln -o -name \*.blg \
-o -name \*.bbl -o -name \*.elc -o -name \*.lof -o -name \*.glo \
-o -name \*.idx -o -name \*.lot -o -name \*.fmt -o -name \*.tfm \
-o -name \*.class -o -name \*.fas -o -name \*.lib -o -name \*.mem \
-o -name \*.x86f -o -name \*.sparcf -o -name \*.fasl -o -name \*.ufsl \
-o -name \*.fsl -o -name \*.dxl -o -name \*.pfsl -o -name \*.dfsl \
-o -name \*.p64fsl -o -name \*.d64fsl -o -name \*.dx64fsl -o -name \*.lo \
-o -name \*.la -o -name \*.gmo -o -name \*.mo -o -name \*.toc \
-o -name \*.aux -o -name \*.cp -o -name \*.fn -o -name \*.ky \
-o -name \*.pg -o -name \*.tp -o -name \*.vr -o -name \*.cps \
-o -name \*.fns -o -name \*.kys -o -name \*.pgs -o -name \*.tps \
-o -name \*.vrs -o -name \*.pyc -o -name \*.pyo \) \
-prune -o \
-type f \( -name pattern \) -print0 \
| xargs -0 -e grep -i -nH -e regex
Он игнорирует каталоги, созданные большинством систем управления версиями, а также сгенерированные файлы для многих языков программирования.
Вы можете создать псевдоним, который вызывает эту команду, и заменять шаблоны find
и grep
для ваших конкретных проблем.
Найти GNU
find . ! -regex ".*[/]\.svn[/]?.*"
Я использую grep для этой цели. Поместите это в свой ~/.bashrc
export GREP_OPTIONS="--binary-files=without-match --color=auto --devices=skip --exclude-dir=CVS --exclude-dir=.libs --exclude-dir=.deps --exclude-dir=.svn"
grep автоматически использует эти параметры при вызове
Создайте script под названием ~/bin/svnfind
:
#!/bin/bash
#
# Attempts to behave identically to a plain `find' command while ignoring .svn/
# directories.
OPTIONS=()
PATHS=()
EXPR=()
while [[ $1 =~ ^-[HLP]+ ]]; do
OPTIONS+=("$1")
shift
done
while [[ $# -gt 0 ]] && ! [[ $1 =~ '^[-(),!]' ]]; do
PATHS+=("$1")
shift
done
# If user expression contains no action then we'll add the normally-implied
# `-print'.
ACTION=-print
while [[ $# -gt 0 ]]; do
case "$1" in
-delete|-exec|-execdir|-fls|-fprint|-fprint0|-fprintf|-ok|-print|-okdir|-print0|-printf|-prune|-quit|-ls)
ACTION=;;
esac
EXPR+=("$1")
shift
done
if [[ ${#EXPR} -eq 0 ]]; then
EXPR=(-true)
fi
exec -a "$(basename "$0")" find "${OPTIONS[@]}" "${PATHS[@]}" -name .svn -type d -prune -o '(' "${EXPR[@]}" ')' $ACTION
Этот script ведет себя одинаково с простой командой find
, но выгружает .svn
каталоги. В противном случае поведение идентично.
Пример:
# svnfind -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) {
./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;
find . | grep -v \.svn
Почему вы не связываете свою команду с grep, что легко понять:
your find command| grep -v '\.svn'
Просто подумал, что добавлю простую альтернативу к сообщениям Kaleb и других пользователей (в которых подробно описываются опции find -prune
, ack
, repofind
и т.д.), что , особенно применимый к использованию, которое вы описали в вопросе (и любых других подобных случаях):
Для производительности вы всегда должны использовать find ... -exec grep ... +
(спасибо Kenji за указание этого) или find ... | xargs egrep ...
(переносимый) или find ... -print0 | xargs -0 egrep ...
(GNU; работает с именами файлов, содержащих пробелы) вместо find ... -exec grep ... \;
.
Форма find ... -exec ... +
и find | xargs
не для fork egrep
для каждого файла, а скорее для группы файлов за раз, в результате чего выполняется намного быстрее.
При использовании формы find | xargs
вы также можете использовать grep
, чтобы легко и быстро обрезать .svn
(или любые каталоги или регулярные выражения), т.е. find ... -print0 | grep -v '/\.svn' | xargs -0 egrep ...
(полезно, когда вам нужно что-то быстрое и может Не надо беспокоиться о том, как настроить логику find
-prune
.)
Подход find | grep | xargs
похож на вариант GNU find
-regex
(см. ghostdog74
post), но более переносимый (также будет работать на платформах, где GNU find
недоступен.)
В репозитории исходного кода я вообще хочу делать что-то только в текстовых файлах.
Первая строка - это все файлы, исключая файлы репозитория 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
Я использую find с параметрами -not -path. Мне не повезло с чернотой.
find . -name "*.groovy" -not -path "./target/*" -print
найдет файлы groovy не в пути к целевому каталогу.
Попробуйте findrepo, который является простой оболочкой find/grep и намного быстрее, чем ack Вы бы использовали его в этом случае, например:
findrepo uint 'messages.*'
wcfind
- это обертка для поиска script, которую я использую для автоматического удаления каталогов .svn.
Чтобы решить эту проблему, вы можете просто использовать это условие поиска:
find \( -name 'messages.*' ! -path "*/.svn/*" \) -exec grep -Iw uint {} +
Вы можете добавить больше ограничений, например:
find \( -name 'messages.*' ! -path "*/.svn/*" ! -path "*/CVS/*" \) -exec grep -Iw uint {} +
Дополнительную информацию об этом можно найти в разделе "Операторы" на странице man: 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 {}
, для файлов NOT внутри каталогов .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
Это работает для меня в приглашении Unix
gfind.\(-not -wholename '*. svn *' \) -type f -name '. *' -exec grep -Iw uint {} +
В приведенной выше команде будут перечислены ФАЙЛЫ, которые не с .svn, и сделанные вами grep.
Я обычно трассирую вывод через grep еще раз, удаляя .svn, в моем использовании он не намного медленнее. типичный пример:
find -name 'messages.*' -exec grep -Iw uint {} + | grep -Ev '.svn|.git|.anythingElseIwannaIgnore'
ИЛИ
find . -type f -print0 | xargs -0 egrep messages. | grep -Ev '.svn|.git|.anythingElseIwannaIgnore'