Как мне заставить `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 ]

284 голосов
/ 20 июля 2010

почему не просто

find . -not -iwholename '*.svn*'

Предикат -not отменяет все, что имеет .svn в любом месте пути.

Так что в вашем случае это будет

find -not -iwholename '*.svn*' -name 'messages.*' -exec grep -Iw uint {} + \;
140 голосов
/ 23 февраля 2010

следующим образом:

find . -path '*/.svn*' -prune -o -print

Или, альтернативно, на основе каталога, а не префикса пути:

find . -name .svn -a -type d -prune -o -print
64 голосов
/ 23 февраля 2010

Для поиска могу ли я предложить вам посмотреть ack ? Он поддерживает исходный код find и поэтому автоматически игнорирует многие типы файлов, включая информацию о хранилище исходного кода, такую ​​как приведенная выше.

30 голосов
/ 20 апреля 2015

Чтобы игнорировать .svn, .git и другие скрытые каталоги (начиная с точки), попробуйте:

find . -type f -not -path '*/\.*'

Однако, если целью использования find является поиск в файлах, вы можете попробовать использовать следующие команды:

  • git grep - специально разработанная команда для поиска шаблонов в репозитории Git.
  • ripgrep - который по умолчанию игнорирует скрытые файлы и файлы, указанные в .gitignore.

Related: Как найти все файлы, содержащие определенный текст в Linux?

18 голосов
/ 21 ноября 2011

Вот что я бы сделал в вашем случае:

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 для ваших конкретных проблем.

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

GNU найти

find .  ! -regex ".*[/]\.svn[/]?.*"
10 голосов
/ 08 марта 2010

Я использую 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 автоматически использует эти опции при вызове

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

find . | grep -v \.svn

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

Создайте скрипт с именем ~/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's 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

Этот скрипт ведет себя идентично простой команде 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;
7 голосов
/ 24 февраля 2010

Почему бы вам не передать команду с помощью grep, который легко понять:

your find command| grep -v '\.svn'
...