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
方法类似于GNUfind
的-regex
选项(参见ghostdog74
的帖子),但更具可移植性(也适用于GNUfind
不可用的平台)
为此,我使用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 '*/\.*'