[linux] 我怎樣才能讓`find`忽略.svn目錄?


8 Answers

為什麼不只是

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

-not謂詞否定在路徑中任何位置具有.svn的所有內容。

所以你的情況是這樣的

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

我經常使用find命令搜索源代碼,刪除文件等等。 令人煩惱的是,由於Subversion在其.svn/text-base/目錄中存儲了每個文件的重複項,我的簡單搜索最終得到了大量重複的結果。 例如,我想遞歸搜索多個messages.hmessages.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忽略.svn目錄?

更新 :如果你升級你的SVN客戶端到1.7版本,這不再是一個問題。

Subversion 1.7引入的變化的一個關鍵特性是將工作副本元數據存儲集中到一個位置。 在工作副本的每個目錄中,Subversion 1.7工作副本只有一個.svn目錄,而不是工作副本的根目錄中的.svn目錄。 該目錄包括(除其他之外)SQLite支持的數據庫,其中包含該工作副本的所有元數據Subversion需求。




GNU查找

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



請注意,如果你這樣做

find . -type f -name 'messages.*'

那麼當整個表達式( -type f -name 'messages.*' )為真時,就會隱含-print ,因為沒有'action'(如-exec )。

當停止下降到某些目錄時,應該使用與這些目錄相匹配的任何內容,並遵循它通過-prune (旨在停止下降到目錄中)。 像這樣:

find . -type d -name '.svn' -prune

對於.svn目錄,它的計算結果為True ,我們可以通過在-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 {} ,對於-name 'message.*' -exec grep -Iw uint {} .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 ,您總是應該在布爾表達式的右側使用'action'。 當這個動作正在打印時,你必須明確地添加它,如下所示:

find . -name '.svn' -prune -o -name 'message.*' -print




創建一個名為~/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;



試試findrepo這是find / grep的一個簡單包裝,比ack快得多你可以在這種情況下使用它:

findrepo uint 'messages.*'



在源代碼庫中,我通常只想對文本文件進行操作。

第一行是所有文件,不包括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



我通常通過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'



為什麼不用grep來管理你的命令,這很容易理解:

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



要忽略.svn.git和其他隱藏目錄(以點開頭),請嘗試:

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



Related