Costumo usar o find
comando para pesquisar no código fonte, excluir arquivos, o que for. Irritantemente, porque o Subversion armazena duplicatas de cada arquivo em seus .svn/text-base/
diretórios, minhas pesquisas simples acabam obtendo muitos resultados duplicados. Por exemplo, desejo pesquisar recursivamente uint
em vários arquivos messages.h
e messages.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;
Como posso dizer find
para ignorar os .svn
diretórios?
Atualização : se você atualizar o seu cliente SVN para a versão 1.7, isso não será mais um problema.
Um recurso importante das alterações introduzidas no Subversion 1.7 é a centralização do armazenamento de metadados da cópia de trabalho em um único local. Em vez de um
.svn
diretório em todos os diretórios da cópia de trabalho, as cópias de trabalho do Subversion 1.7 têm apenas um.svn
diretório - na raiz da cópia de trabalho. Este diretório inclui (entre outras coisas) um banco de dados baseado em SQLite que contém todos os metadados que o Subversion precisa para essa cópia de trabalho.
find ... -print0 | xargs -0 egrep ...
vez defind ... -exec grep ...
(não bifurcagrep
para cada arquivo, mas para vários arquivos por vez). Usando este formulário, você também pode remover.svn
diretórios sem usar a-prune
opção find, ou seja,find ... -print0 | egrep -v '/\.svn' | xargs -0 egrep ...
-exec
com+
não bifurcagrep
para cada arquivo, enquanto usá-lo com;
faz. Usar-exec
é realmente mais correto do que usarxargs
. Observe que comandos comols
fazem algo mesmo que a lista de argumentos esteja vazia, enquanto comandos comochmod
dão um erro se houver argumentos insuficientes. Para ver o que quero dizer, tente o seguinte comando em um diretório que não tem qualquer script shell:find /path/to/dir -name '*.sh' -print0 | xargs -0 chmod 755
. Compare com esta:find /path/to/dir -name '*.sh' -exec chmod 755 '{}' '+'
.grep
sair.svn
também não é uma boa ideia. Enquantofind
é especializado para manipular propriedades de arquivo,grep
não. No seu exemplo, um arquivo chamado '.svn.txt' também será filtrado pelo seuegrep
comando. Embora você possa modificar seu regex para '^ / \. Svn $' , ainda não é uma boa prática fazer isso. O-prune
predicadofind
funciona perfeitamente para filtrar um arquivo (por nome de arquivo ou carimbo de data / hora da criação ou qualquer condição que você forneceu). É como se você pudesse matar uma barata usando uma espada grande, não significa que é a maneira sugerida de fazê-lo :-).Respostas:
Para pesquisar, posso sugerir que você olhe para ack ? É compatível com o código-fonte e
find
, como tal, ignorará automaticamente muitos tipos de arquivos, incluindo informações sobre o repositório do código-fonte, como o descrito acima.fonte
ack
muito, mas achei que era substancialmente mais lento do quefind -type f -name "*.[ch]" | xargs grep
quando lida com uma grande base de código.ack
faturamento não é melhorgrep
, nem reconhece a fontefind
? Alguns exemplos de como substituífind
-lo tornariam essa uma resposta real.porque não apenas
O predicado -not nega tudo o que tem .svn em qualquer lugar do caminho.
Então, no seu caso, seria
fonte
'*.svn*'
no começo, mas depois'*.svn'
. Qual é certo? Os dois funcionam? Eu acho que provavelmente deveria ser'*.svn*'
?Do seguinte modo:
Ou, alternativamente, com base em um diretório e não em um prefixo de caminho:
fonte
find . -type d -name .svn -prune -o -print
porque é um pouco mais rápido. De acordo com o padrão POSIX , as expressões são avaliadas uma a uma, na ordem especificada. Se a primeira expressão em-a
forfalse
, a segunda expressão não será avaliada (também chamada de curto-circuito e avaliação ).-type d
antes-name .svn
é teoricamente mais eficiente. No entanto, geralmente é insignificante, exceto se você tiver uma árvore de diretórios muito grande.-print
parte da última expressão. Algo comofind . -name .git -prune -o \( -type f -name LICENSE -print \)
funciona como esperado.find . -name .svn -prune -o -name .git -prune -o -type d -print
,. Pode ser alguns milissegundos mais rápido-type d
antes dos dois-name
, mas não vale a pena digitar mais.Para ignorar
.svn
,.git
e outros diretórios ocultos (que começam com um ponto), tente:No entanto, se o objetivo de usar
find
estiver pesquisando nos arquivos, você pode tentar usar estes comandos:git grep
- comando especialmente projetado para pesquisar padrões no repositório Git.ripgrep
- que por padrão ignora arquivos ocultos e arquivos especificados em.gitignore
.Relacionado: Como encontro todos os arquivos que contêm texto específico no Linux?
fonte
Aqui está o que eu faria no seu caso:
O
rgrep
comando interno do Emacs ignora o.svn
diretório e muitos outros arquivos nos quais você provavelmente não está interessado ao executar umfind | grep
. Aqui está o que ele usa por padrão:Ele ignora os diretórios criados pela maioria dos sistemas de controle de versão, além de gerar arquivos para muitas linguagens de programação. Você pode criar um alias que chama esse comando e substituir
find
egrep
padrões para seus problemas específicos.fonte
Localização GNU
fonte
-type d
) - essa resposta foi. +1Eu uso grep para esse fim. Coloque isso no seu ~ / .bashrc
O grep usa automaticamente essas opções na invocação
fonte
GREP_OPTIONS=xxx grep "$@"
. Isso significa que a variável GREP_OPTIONS é definida apenas para instâncias do grep executadas manualmente usando 'grp'. Isso significa que nunca recebo uma situação em que executo uma ferramenta e, internamente, ela chama grep, mas a ferramenta fica confusa porque o grep não está se comportando conforme o esperado. Além disso, tenho uma segunda função 'grpy', que chama 'grp', mas acrescenta--include=*.py
, apenas para pesquisar arquivos Python.grep --exclude=tags --exclude_dir=.git ...etc... "$@"
. Gosto que isso funcione como 'ack', mas mantenho a consciência e o controle sobre o que está fazendo.find . | grep -v \.svn
fonte
.
na.svn
regexp.| fgrep -v /.svn/
ou `| grep -F -v / .svn / `para excluir exatamente o diretório e não os arquivos com" .svn "como parte de seu nome.Por que você não canaliza seu comando com grep, que é facilmente compreensível:
fonte
.
na.svn
regexp.Crie um script chamado
~/bin/svnfind
:Esse script se comporta de maneira idêntica a um
find
comando simples, mas remove os.svn
diretórios. Caso contrário, o comportamento é idêntico.Exemplo:
fonte
echo
ao comando find e me dizer qual comando é executado?svnfind -type f
funciona muito bem na minha máquina Red Hat.echo find "${OPTIONS[@]}"...
para que ele imprima o comando find em vez de executá-lo.echo find ${OPTIONS[@]} ${PATHS[@]} -name .svn -type d -prune -o ( ${EXPR[@]} ) $ACTION
, Isso me dá a seguinte saída:find -type f -name .svn -type d -prune -o ( -true ) -print
Apenas pensei em adicionar uma alternativa simples às postagens de Kaleb e de outras pessoas (que detalham o uso da
find -prune
opçãoack
,repofind
comandos , etc.), que é particularmente aplicável ao uso que você descreveu na pergunta (e qualquer outro uso semelhante):Para desempenho, você deve sempre tentar usar
find ... -exec grep ... +
(obrigado Kenji por apontar isso) oufind ... | xargs egrep ...
(portátil) oufind ... -print0 | xargs -0 egrep ...
(GNU; funciona em nomes de arquivos contendo espaços) em vez defind ... -exec grep ... \;
.O formulário
find ... -exec ... +
efind | xargs
não bifurcaegrep
para cada arquivo, mas para vários arquivos por vez, resultando em uma execução muito mais rápida .Ao utilizar o
find | xargs
formulário que você também pode usargrep
a facilidade e rapidez de ameixa.svn
(ou quaisquer diretórios ou expressão regular), ou seja,find ... -print0 | grep -v '/\.svn' | xargs -0 egrep ...
(útil quando você precisa de algo rápido e não pode ser incomodado para lembrar como configurarfind
's-prune
lógica.)A
find | grep | xargs
abordagem é semelhante GNU parafind
's-regex
opção (verghostdog74
' s post), mas é mais portátil (também funcionará em plataformas onde GNUfind
não está disponível.)fonte
-exec
trocafind
: um está terminando com;
e o outro está terminando com+
. O que termina com+
substitui{}
por uma lista de todos os arquivos correspondentes. Além disso, seu regex também'/\.svn'
combina nomes de arquivos'.svn.txt'
. Por favor, consulte meus comentários na pergunta para obter mais informações.find
utilitário. Por favor, veja a-exec
parte :-).Em um repositório de código-fonte, geralmente quero fazer as coisas apenas com os arquivos de texto.
A primeira linha são todos os arquivos, excluindo os arquivos de repositório CVS, SVN e GIT.
A segunda linha exclui todos os arquivos binários.
fonte
Eu uso find com as opções -not -path. Não tive boa sorte com ameixa.
encontrará os arquivos groovy que não estão no caminho do diretório de destino.
fonte
Para resolver esse problema, você pode simplesmente usar esta condição de localização:
Você pode adicionar mais restrições como esta:
Você pode encontrar mais informações sobre isso na seção "Operadores" da página de manual: http://unixhelp.ed.ac.uk/CGI/man-cgi?find
fonte
Observe que se você fizer
find . -type f -name 'messages.*'
então
-print
é implícito quando toda a expressão (-type f -name 'messages.*'
) é verdadeira, porque não há 'ação' (como-exec
).Enquanto, para parar de descer para determinados diretórios, você deve usar qualquer coisa que corresponda a esses diretórios e segui-lo
-prune
(que se destina a parar de descer para diretórios); igual a:find . -type d -name '.svn' -prune
Isso é avaliado como True para os diretórios .svn, e podemos usar um curto-circuito booleano seguindo isto por
-o
(OR), após o qual o que se segue após o-o
é verificado apenas quando a primeira parte é False, portanto, não é um diretório .svn. Em outras palavras, o seguinte:find . -type d -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}
só evalute o que é certo do
-o
, ou seja-name 'message.*' -exec grep -Iw uint {}
, para arquivos não dentro diretórios .svn.Observe que, como
.svn
provavelmente sempre é um diretório (e não, por exemplo, um arquivo), e, nesse caso, certamente não corresponde ao nome 'message. *', Você também pode deixar de lado o seguinte-type d
comando:find . -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}
Por fim, observe que, se você omitir qualquer ação (
-exec
é uma ação), diga o seguinte:find . -name '.svn' -prune -o -name 'message.*'
a
-print
ação é implícita, mas será aplicada à expressão WHOLE, incluindo a-name '.svn' -prune -o
parte e, assim, imprima todos os diretórios .svn, bem como os arquivos 'message. *', o que provavelmente não é o que você deseja. Portanto, você sempre deve usar uma 'ação' no lado direito da expressão booleana ao usá-prune
-lo dessa maneira. E quando essa ação está sendo impressa, você deve adicioná-la explicitamente, assim:find . -name '.svn' -prune -o -name 'message.*' -print
fonte
Tente findrepo, que é um invólucro simples em torno de find / grep e muito mais rápido que o ack. Você usaria neste caso como:
fonte
wcfind
é um script de wrapper de localização que eu uso para remover automaticamente diretórios .svn.fonte
Isso funciona para mim no prompt do Unix
O comando acima listará FILES que não estão com .svn e executará o grep que você mencionou.
fonte
xxx.svnxxx
. Isso é importante - por exemplo, se você estiver usando git em vez de svn, geralmente desejará incluir arquivos como .gitignore (que não são metadados, é um arquivo comum incluído no repositório) nos resultados da localização.Eu normalmente canalizo a saída através do grep mais uma vez removendo .svn, no meu uso, não é muito mais lento. exemplo típico:
OU
fonte