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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2314643/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:48:17  来源:igfitidea点击:

How can I get `find` to ignore .svn directories?

linuxfindbashgrepsvn

提问by John Kugelman

I often use the findcommand to search through source code, delete files, whatever. Annoyingly, because Subversion stores duplicates of each file in its .svn/text-base/directories my simple searches end up getting lots of duplicate results. For example, I want to recursively search for uintin multiple messages.hand messages.cppfiles:

我经常使用该find命令来搜索源代码、删除文件等等。令人讨厌的是,因为 Subversion 在其.svn/text-base/目录中存储了每个文件的重复项,所以我的简单搜索最终会得到很多重复的结果。例如,我想uint在多个messages.hmessages.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;

How can I tell findto ignore the .svndirectories?

我怎么知道find要忽略.svn目录?



Update: If you upgrade your SVN client to version 1.7this is no longer an issue.

更新:如果您将 SVN 客户端升级到1.7 版,这不再是问题。

A key feature of the changes introduced in Subversion 1.7 is the centralization of working copy metadata storage into a single location. Instead of a .svndirectory in every directory in the working copy, Subversion 1.7 working copies have just one .svndirectory—in the root of the working copy. This directory includes (among other things) an SQLite-backed database which contains all of the metadata Subversion needs for that working copy.

Subversion 1.7 中引入的更改的一个关键特性是将工作副本元数据存储集中到一个位置。.svnSubversion 1.7 工作副本只有一个.svn目录——工作副本的根目录,而不是在工作副本的每个目录中都有一个目录。该目录包括(除其他外)一个 SQLite 支持的数据库,其中包含 Subversion 对该工作副本所需的所有元数据。

采纳答案by Brian Agnew

For searching, can I suggest you look at ack? It's a source-code aware find, and as such will automatically ignore many file types, including source code repository info such as the above.

对于搜索,我可以建议您查看ack吗?它是一个源代码感知的find,因此会自动忽略许多文件类型,包括源代码存储库信息,如上述。

回答by John Kugelman

Create a script called ~/bin/svnfind:

创建一个名为 的脚本~/bin/svnfind

#!/bin/bash
#
# Attempts to behave identically to a plain `find' command while ignoring .svn/
# directories.

OPTIONS=()
PATHS=()
EXPR=()

while [[  =~ ^-[HLP]+ ]]; do
    OPTIONS+=("")
    shift
done

while [[ $# -gt 0 ]] && ! [[  =~ '^[-(),!]' ]]; do
    PATHS+=("")
    shift
done

# If user's expression contains no action then we'll add the normally-implied
# `-print'.
ACTION=-print

while [[ $# -gt 0 ]]; do
    case "" in
       -delete|-exec|-execdir|-fls|-fprint|-fprint0|-fprintf|-ok|-print|-okdir|-print0|-printf|-prune|-quit|-ls)
            ACTION=;;
    esac

    EXPR+=("")
    shift
done

if [[ ${#EXPR} -eq 0 ]]; then
    EXPR=(-true)
fi

exec -a "$(basename "
# 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 "${OPTIONS[@]}" "${PATHS[@]}" -name .svn -type d -prune -o '(' "${EXPR[@]}" ')' $ACTION

This script behaves identically to a plain findcommand but it prunes out .svndirectories. Otherwise the behavior is identical.

此脚本的行为与普通find命令相同,但它会删除.svn目录。否则行为是相同的。

Example:

例子:

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

回答by Kaleb Pederson

As follows:

如下:

find . -name .svn -a -type d -prune -o -print

Or, alternatively based on a directory and not a path prefix:

或者,或者基于目录而不是路径前缀:

find .  ! -regex ".*[/]\.svn[/]?.*"

回答by ghostdog74

GNU find

GNU 查找

findrepo uint 'messages.*'

回答by pixelbeat

Try findrepowhich is a simple wrapper around find/grep and much faster than ack You would use it in this case like:

试试findrepo,它是一个简单的 find/grep 包装器,比 ack 快得多,你可以在这种情况下使用它,例如:

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

回答by me.

find . | grep -v \.svn

find . | grep -v \.svn

回答by Vijay

Why dont you pipe your command with grep which is easily understandable:

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

export GREP_OPTIONS="--binary-files=without-match --color=auto --devices=skip --exclude-dir=CVS --exclude-dir=.libs --exclude-dir=.deps --exclude-dir=.svn"

回答by leedm777

wcfindis a find wrapper script that I use to automagically remove .svn directories.

wcfind是我用来自动删除 .svn 目录的查找包装脚本。

回答by vladr

Just thought I'd add a simple alternativeto Kaleb's and others' posts (which detailed the use of the find -pruneoption, ack, repofindcommands etc.) which is particularly applicable to the usage you have described in the question(and any other similar usages):

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

  1. For performance, you should always try to use find ... -exec grep ... +(thanks Kenji for pointing this out) or find ... | xargs egrep ...(portable) or find ... -print0 | xargs -0 egrep ...(GNU; works on filenames containing spaces) insteadof find ... -exec grep ... \;.

    The find ... -exec ... +and find | xargsform does not fork egrepfor each file, but rather for a bunch of files at a time, resulting in much faster execution.

  2. When using the find | xargsform you can also use grepto easily and quickly prune .svn(or any directories or regular expression), i.e. find ... -print0 | grep -v '/\.svn' | xargs -0 egrep ...(useful when you need something quick and can't be bothered to remember how to set up find's -prunelogic.)

    The find | grep | xargsapproach is similar to GNU find's -regexoption (see ghostdog74's post), but is more portable (will also work on platforms where GNU findis not available.)

  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方法类似于 GNUfind-regex选项(请参阅ghostdog74的帖子),但更具可移植性(也适用于 GNUfind不可用的平台。)

回答by Ronny Brendel

I use grep for this purpose. Put this in your ~/.bashrc

为此,我使用 grep。把它放在你的 ~/.bashrc 中

##代码##

grep automatically uses these options on invocation

grep 在调用时自动使用这些选项