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

Joh*_*ica 221 linux svn bash grep find

我经常使用该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;
Run Code Online (Sandbox Code Playgroud)

如何判断find忽略.svn目录?


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

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

wha*_*ley 290

为什么不呢

find . -not -iwholename '*.svn*'
Run Code Online (Sandbox Code Playgroud)

-not谓词否定了路径中任何地方的.svn.

所以在你的情况下它会

find -not -iwholename '*.svn*' -name 'messages.*' -exec grep -Iw uint {} + \;
Run Code Online (Sandbox Code Playgroud)

  • 我已经离开了我的元素,我确信我会因为这个评论而受到批评,但显然-not和-wholename不符合POSIX标准.我用了 !用-not和-path代替-iwholename,得到相同的结果.根据我的手册页(Ubuntu 12.04),这种语法符合POSIX标准. (13认同)
  • 实际回答原始问题的唯一回应. (9认同)
  • "-not"和"-iwholename"的超级大+1.Ack非常好,我使用它,但发现/ exec仍然有它的用途. (4认同)

Kal*_*son 140

如下:

find . -path '*/.svn*' -prune -o -print
Run Code Online (Sandbox Code Playgroud)

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

find . -name .svn -a -type d -prune -o -print
Run Code Online (Sandbox Code Playgroud)

  • @Kaleb:嗨.我建议**`找到.-type d -name .svn -prune -o -print`**因为它有点快.根据[POSIX标准](http://www.opengroup.org/onlinepubs/9699919799/utilities/find.html),按指定的顺序逐个评估表达式.如果`-a`中的第一个表达式是'false`,则不会评估第二个表达式(也称为[短路和评估](http://en.wikipedia.org/wiki/Short-circuit_evaluation)). (13认同)
  • @ SiuChingPong-AsukaKenji-不,只比较文件名更快,因为-type需要对每个文件进行stat(2)调用.但是,文件名是readdir(3)响应的一部分. (4认同)
  • @JonathanHartley你错过了`-print`作为最后一个表达式的一部分.像找到的东西.-name .git -prune -o \( - type f -name LICENSE -print \)`按预期工作. (3认同)
  • @Kaleb:比较**文件类型**(相当于测试一个位是否设置为整数)比**文件****(相当于字符串比较,即O)更快**n)),在`-name .svn`之前放置`-type d`在理论上更有效.但是,它通常是无关紧要的,除非你有一个非常大的目录树. (2认同)

Bri*_*new 65

为了搜索,我可以建议你看看ack吗?它是源代码识别的find,因此会自动忽略许多文件类型,包括上面的源代码存储库信息.

  • 约翰,我是ack的作者,如果你能给我详细说明ack与grep的速度问题,我会很感激.在我发现的所有案例中,它们都是完全可比的.或者通过http://github.com/petdance/ack/issues告诉我,或者发送电子邮件给我在petdance.com的安迪.Thansk. (63认同)
  • 伙计们,这是一个提示,但绝对不是问题的答案!:) (60认同)
  • 是不是'ack`被称为更好的'grep`,而不是源于感知的`find`?使用它来代替`find`的一些例子会使这成为一个真正的答案. (8认同)
  • 我非常喜欢`ack`,但我发现它比`find -type f -name"*慢得多.[ch]"| 处理大型代码库时xargs grep`. (3认同)
  • 这是他不知道他问的问题的答案.=) (3认同)
  • @AndyLester我刚刚跑了`ack --bar`.......太棒了,谢谢. (3认同)

ken*_*orb 31

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

find . -type f -not -path '*/\.*'
Run Code Online (Sandbox Code Playgroud)

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

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

相关:如何在Linux上找到包含特定文本的所有文件?


Ant*_*ine 18

这是我在你的情况下会做的:

find . -path .svn -prune -o -name messages.* -exec grep -Iw uint {} +
Run Code Online (Sandbox Code Playgroud)

Emacs的rgrep内置命令会忽略.svn目录,以及执行a时可能不感兴趣的更多文件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
Run Code Online (Sandbox Code Playgroud)

它忽略了大多数版本控制系统创建的目录,以及许多编程语言的生成文件.您可以创建一个别名来调用此命令,并替换findgrep模式以解决您的特定问题.


gho*_*g74 12

GNU找到

find .  ! -regex ".*[/]\.svn[/]?.*"
Run Code Online (Sandbox Code Playgroud)


Ron*_*del 10

我为此目的使用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"
Run Code Online (Sandbox Code Playgroud)

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


Joh*_*ica 8

创建一个名为的脚本~/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
Run Code Online (Sandbox Code Playgroud)

此脚本的行为与普通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;
Run Code Online (Sandbox Code Playgroud)


小智 8

find . | grep -v \.svn

  • 使用* - fixed-strings*和grep:`| fgrep -v/.svn /`或`| grep -F -v/.svn /`排除*恰好*目录而不是".svn"作为其名称的一部分的文件. (4认同)

Vij*_*jay 7

为什么不用grep管理你的命令,这很容易理解:

your find command| grep -v '\.svn'
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这个答案,因为它在概念上比所有其他答案都简单.我不记得'find'用法的荒谬语法,但我绝对记得如何使用grep -v,因为它在很多情况下使用. (2认同)

vla*_*adr 5

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

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

  • @Vlad:[here](http://www.opengroup.org/onlinepubs/9699919799/utilities/find.html)是**`find`**实用程序的POSIX标准.请参阅**`-exec`**部分:-). (2认同)