Linux 如何让'find'忽略.svn目录?

Linux 如何让'find'忽略.svn目录?,linux,find,bash,grep,svn,Linux,Find,Bash,Grep,Svn,我经常使用find命令来搜索源代码、删除文件等等。令人烦恼的是,由于Subversion在其.svn/text base/目录中存储每个文件的副本,因此我的简单搜索最终会得到大量重复的结果。例如,我想在多个messages.h和messages.cpp文件中递归搜索uint: # find -name 'messages.*' -exec grep -Iw uint {} + ./messages.cpp: Log::verbose << "Discarding

我经常使用
find
命令来搜索源代码、删除文件等等。令人烦恼的是,由于Subversion在其
.svn/text base/
目录中存储每个文件的副本,因此我的简单搜索最终会得到大量重复的结果。例如,我想在多个
messages.h
messages.cpp
文件中递归搜索
uint

# 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-name'消息。*'-exec grep-Iw uint{}+

./messages.cpp:Log::verbose创建一个名为
~/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;
#svnfind-name“messages.*'-exec grep-Iw uint{}+

./messages.cpp:Log::verbose对于搜索,我可以建议您查看吗?它是一个支持源代码的查找程序,因此会自动忽略许多文件类型,包括上述源代码存储库信息。

如下所示:

find . -path '*/.svn*' -prune -o -print
或者,基于目录而不是路径前缀:

find . -name .svn -a -type d -prune -o -print
GNU查找

find .  ! -regex ".*[/]\.svn[/]?.*"
试试看,这是一个简单的find/grep包装器,比ack快得多 在这种情况下,您可以像这样使用它:

findrepo uint 'messages.*'

find.|grep-v\.svn

为什么不使用易于理解的grep来执行命令:

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

是一个查找包装器脚本,我用它自动删除.svn目录。

我只是想给Kaleb和其他人的帖子添加一个简单的替代方案(详细说明了
find-prune
选项、
ack
repofind
命令等的使用。)特别适用于您在问题中描述的用法(以及任何其他类似用法):

  • 为了提高性能,您应该始终尝试使用
    find-执行官格雷普+
    (感谢Kenji指出这一点)或
    查找…|xargs egrep…
    (便携式)或
    查找-print0 | xargs-0 egrep…
    (GNU;适用于包含空格的文件名)而不是
    查找-执行官格雷普…\

    查找-执行+
    find | xargs
    表单不会为每个文件分叉
    egrep
    ,而是一次为一组文件分叉,导致执行速度大大加快

  • 使用
    find | xargs
    表单时,您还可以使用
    grep
    轻松快速地修剪
    .svn
    (或任何目录或正则表达式),即
    find-print0 | grep-v'/\.svn'| xargs-0 egrep…
    (当您需要一些快速的东西,并且不需要费心记住如何设置
    查找
    -prune
    逻辑时,此功能非常有用。)

    find | grep | xargs
    方法类似于GNU
    find
    -regex
    选项(参见
    ghostdog74
    的帖子),但更具可移植性(也适用于GNU
    find
    不可用的平台)


  • 为此,我使用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在调用时自动使用这些选项

    为什么不

    find . -not -iwholename '*.svn*'
    
    not谓词否定路径中任何位置具有.svn的所有内容

    所以在你的情况下是这样的

    find -not -iwholename '*.svn*' -name 'messages.*' -exec grep -Iw uint {} + \;
    

    在你的情况下,我会这样做:

    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
    模式。

    这在Unix提示符下对我有效

    格芬德\(-not-wholename'*\.svn*'\)-type f-name'messages.*' -执行官grep-Iw uint{}+


    上面的命令将列出不带.svn的文件,并执行您提到的grep。

    我通常会通过grep再次管道输出删除.svn,在我的使用中,它不会慢很多。 典型示例:

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


    在源代码存储库中,我通常只想对文本文件执行操作

    第一行是所有文件,不包括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文件不在目标目录路径中

    要解决此问题,只需使用以下查找条件:

    find \( -name 'messages.*' ! -path "*/.svn/*" \) -exec grep -Iw uint {} +
    
    您可以像这样添加更多限制:

    find \( -name 'messages.*' ! -path "*/.svn/*" ! -path "*/CVS/*" \) -exec grep -Iw uint {} +
    
    您可以在手册页的“操作员”部分中找到有关此操作的更多信息:

    要忽略
    .svn
    .git
    和其他隐藏目录(以点开头),请尝试:


    但是,如果使用
    find
    的目的是在文件中搜索,则可以尝试使用以下命令:

    • git grep
      -专门设计的命令,用于在git存储库中搜索模式
    • -默认情况下忽略隐藏文件和
      .gitignore
      中指定的文件
    相关:

    请注意,如果

    find-键入f-名称“messages.*”

    然后,当整个表达式(
    -type f-name'messages.*'
    )为真时,将隐含
    -print
    ,因为没有“action”(如
    -exec

    然而,要停止下降到某些目录中,您应该使用与这些目录匹配的任何内容,然后使用
    -prune
    (其目的是停止下降到目录中);像这样:

    find-键入d-name'.svn'-prune

    对于.svn目录,其计算结果为True,我们可以使用布尔短路,方法是按
    -o
    (OR)执行,之后是aft
    find \( -name 'messages.*' ! -path "*/.svn/*" ! -path "*/CVS/*" \) -exec grep -Iw uint {} +
    
    find . -type f -not -path '*/\.*'