A menudo uso el find
comando para buscar a través del código fuente, eliminar archivos, lo que sea. Molesto, debido a que Subversion almacena duplicados de cada archivo en sus .svn/text-base/
directorios, mis búsquedas simples terminan obteniendo muchos resultados duplicados. Por ejemplo, quiero buscar recursivamente uint
en múltiples messages.h
y messages.cpp
archivos:
# 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;
¿Cómo puedo decir find
que ignore los .svn
directorios?
Actualización : si actualiza su cliente SVN a la versión 1.7, esto ya no es un problema.
Una característica clave de los cambios introducidos en Subversion 1.7 es la centralización del almacenamiento de metadatos de la copia de trabajo en una sola ubicación. En lugar de un
.svn
directorio en cada directorio de la copia de trabajo, las copias de trabajo de Subversion 1.7 tienen un solo.svn
directorio, en la raíz de la copia de trabajo. Este directorio incluye (entre otras cosas) una base de datos respaldada por SQLite que contiene todas las necesidades de Subversion de metadatos para esa copia de trabajo.
find ... -print0 | xargs -0 egrep ...
lugar defind ... -exec grep ...
(no se bifurcagrep
para cada archivo, sino para un montón de archivos a la vez). Con este formulario también puede podar.svn
directorios sin usar la-prune
opción de buscar, es decirfind ... -print0 | egrep -v '/\.svn' | xargs -0 egrep ...
-exec
with+
no forkgrep
para cada archivo, mientras que usarlo con;
does. Usar-exec
es en realidad más correcto que usarxargs
. Tenga en cuenta que los comandos comols
hacer algo, incluso si la lista de argumentos está vacía, mientras que los comandos comochmod
dan un error si no hay suficientes argumentos. Para ver lo que quiero decir, sólo tratar el siguiente comando en un directorio que no tiene ningún script de shell:find /path/to/dir -name '*.sh' -print0 | xargs -0 chmod 755
. Comparar con éste:find /path/to/dir -name '*.sh' -exec chmod 755 '{}' '+'
.grep
salir.svn
no es una buena idea también. Si bienfind
está especializado para manejar propiedades de archivos,grep
no lo hace. En su ejemplo, su comando también filtrará un archivo llamado '.svn.txt'egrep
. Aunque puede modificar su expresión regular a '^ / \. Svn $' , aún no es una buena práctica hacerlo. El-prune
predicado defind
funciona perfectamente para filtrar un archivo (por nombre de archivo, o marca de tiempo de creación, o cualquier condición que haya proporcionado). Es como si incluso pudieras matar una cucaracha usando una gran espada, no significa que sea la forma sugerida de hacerlo :-).Respuestas:
Para buscar, ¿puedo sugerirle que mire ack ? Es consciente del código fuente y
find
, como tal, ignorará automáticamente muchos tipos de archivos, incluida la información del repositorio de código fuente, como la anterior.fuente
ack
mucho, pero he encontrado que es sustancialmente más lento quefind -type f -name "*.[ch]" | xargs grep
cuando se trata de una gran base de código.ack
factura como mejorgrep
, no como fuente conscientefind
? Algunos ejemplos de su uso para reemplazarfind
harían de esto una respuesta real.por qué no solo
El predicado -not niega todo lo que tiene .svn en cualquier parte de la ruta.
Entonces en tu caso sería
fuente
'*.svn*'
al principio pero luego'*.svn'
. ¿Lo cual está bien? ¿Ambos funcionan? Creo que probablemente debería ser'*.svn*'
?Como sigue:
O, alternativamente, basado en un directorio y no en un prefijo de ruta:
fuente
find . -type d -name .svn -prune -o -print
porque es un poco más rápido. Según el estándar POSIX , las expresiones se evalúan una por una, en el orden especificado. Si la primera expresión en-a
esfalse
, la segunda expresión no será evaluada (también llamada cortocircuito y evaluación ).-type d
antes-name .svn
es teóricamente más eficiente. Sin embargo, generalmente es insignificante, excepto si tiene un árbol de directorios muy grande.-print
como parte de la última expresión. Algo asífind . -name .git -prune -o \( -type f -name LICENSE -print \)
funciona como se esperaba.find . -name .svn -prune -o -name .git -prune -o -type d -print
. Puede ser unos pocos milisegundos más rápido-type d
antes de los dos-name
, pero no vale la pena escribir más.Para ignorar
.svn
,.git
y otros directorios ocultos (comenzando con un punto), intente:Sin embargo, si el propósito de usar
find
es buscar dentro de los archivos, puede intentar usar estos comandos:git grep
- comando especialmente diseñado para buscar patrones dentro del repositorio de Git.ripgrep
- que por defecto ignora los archivos ocultos y los archivos especificados en.gitignore
.Relacionado: ¿Cómo encuentro todos los archivos que contienen texto específico en Linux?
fuente
Esto es lo que haría en su caso:
El
rgrep
comando incorporado de Emacs ignora el.svn
directorio, y muchos más archivos que probablemente no le interesen al realizar unfind | grep
. Esto es lo que usa por defecto:Ignora los directorios creados por la mayoría de los sistemas de control de versiones, así como los archivos generados para muchos lenguajes de programación. Puede crear un alias que invoque este comando y reemplazar
find
ygrep
patrones para sus problemas específicos.fuente
GNU encontrar
fuente
-type d
), esta respuesta sí. +1Yo uso grep para este propósito. Pon esto en tu ~ / .bashrc
grep usa automáticamente estas opciones en la invocación
fuente
GREP_OPTIONS=xxx grep "$@"
. Esto significa que la variable GREP_OPTIONS solo se establece para instancias de grep que ejecuto manualmente usando 'grp'. Esto significa que nunca tengo una situación en la que ejecuto una herramienta, e internamente se llama grep, pero la herramienta se confunde porque grep no se comporta como esperaba. Además, tengo una segunda función 'grpy', que llama 'grp', pero agrega--include=*.py
, solo para buscar archivos de Python.grep --exclude=tags --exclude_dir=.git ...etc... "$@"
. Me gusta que esto funcione como 'ack', pero conservo conciencia y control sobre lo que está haciendo.find . | grep -v \.svn
fuente
.
en la.svn
expresión regular.| fgrep -v /.svn/
o `| grep -F -v / .svn / `para excluir exactamente el directorio y no los archivos con" .svn "como parte de su nombre.¿Por qué no canaliza su comando con grep, que es fácilmente comprensible?
fuente
.
en la.svn
expresión regular.Crea un script llamado
~/bin/svnfind
:Este script se comporta de manera idéntica a un
find
comando simple pero elimina.svn
directorios. De lo contrario, el comportamiento es idéntico.Ejemplo:
fuente
echo
comando de búsqueda y decirme qué comando se ejecuta?svnfind -type f
funciona muy bien en mi máquina Red Hat.echo find "${OPTIONS[@]}"...
que imprima el comando de búsqueda en lugar de ejecutarlo realmente.echo find ${OPTIONS[@]} ${PATHS[@]} -name .svn -type d -prune -o ( ${EXPR[@]} ) $ACTION
, Esto me da el siguiente resultado:find -type f -name .svn -type d -prune -o ( -true ) -print
Solo pensé que agregaría una alternativa simple a las publicaciones de Kaleb y de otros (que detalla el uso de la
find -prune
opciónack
,repofind
comandos , etc.) que es particularmente aplicable al uso que ha descrito en la pregunta (y cualquier otro uso similar):Para el rendimiento, siempre debe intentar usar
find ... -exec grep ... +
(gracias Kenji por señalar esto) ofind ... | xargs egrep ...
(portátil) ofind ... -print0 | xargs -0 egrep ...
(GNU; funciona en nombres de archivos que contienen espacios) en lugar defind ... -exec grep ... \;
.El formulario
find ... -exec ... +
yfind | xargs
no se bifurcaegrep
para cada archivo, sino para un montón de archivos a la vez, lo que resulta en una ejecución mucho más rápida .Al usar el
find | xargs
formulario, también puede usarlogrep
para podar fácil y rápidamente.svn
(o cualquier directorio o expresión regular), es decirfind ... -print0 | grep -v '/\.svn' | xargs -0 egrep ...
(útil cuando necesita algo rápido y no puede molestarse en recordar cómo configurarfind
la-prune
lógica).El
find | grep | xargs
enfoque es similar afind
la-regex
opción de GNU (veaghostdog74
la publicación de), pero es más portátil (también funcionará en plataformas donde GNUfind
no está disponible).fuente
-exec
cambiofind
: una termina con;
y la otra termina con+
. El que termina con+
reemplaza{}
por una lista de todos los archivos coincidentes. Además, tu expresión regular también'/\.svn'
coincide con los nombres de los archivos'.svn.txt'
. Consulte mis comentarios a la pregunta para obtener más información.find
utilidad. Por favor vea la-exec
parte :-).En un repositorio de código fuente, generalmente quiero hacer cosas solo con los archivos de texto.
La primera línea son todos los archivos, excepto los archivos de repositorio CVS, SVN y GIT.
La segunda línea excluye todos los archivos binarios.
fuente
Yo uso find con las opciones -not -path. No he tenido buena suerte con la ciruela pasa.
encontrará los archivos geniales que no están en la ruta del directorio de destino.
fuente
Para resolver este problema, simplemente puede usar esta condición de búsqueda:
Puede agregar más restricciones como esta:
Puede encontrar más información sobre esto en la sección de la página de manual "Operadores": http://unixhelp.ed.ac.uk/CGI/man-cgi?find
fuente
Tenga en cuenta que si lo hace
find . -type f -name 'messages.*'
entonces
-print
está implícito cuando toda la expresión (-type f -name 'messages.*'
) es verdadera, porque no hay 'acción' (como-exec
).Mientras que, para dejar de descender a ciertos directorios, debe usar cualquier cosa que coincida con esos directorios y seguirlo
-prune
(que tiene la intención de dejar de descender a directorios); al igual que:find . -type d -name '.svn' -prune
Esto se evalúa como Verdadero para los directorios .svn, y podemos usar un cortocircuito booleano siguiendo esto por
-o
(OR), después de lo cual lo que sigue después de-o
que solo se verifica cuando la primera parte es Falso, por lo tanto, no es un directorio .svn. En otras palabras, lo siguiente:find . -type d -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}
solo evaluará lo que es correcto de
-o
, es decir-name 'message.*' -exec grep -Iw uint {}
, para archivos que NO estén dentro de directorios .svn.Tenga en cuenta que debido a que
.svn
es probable que siempre sea un directorio (y no, por ejemplo, un archivo), y en este caso ciertamente no coincide con el nombre 'mensaje. *', También podría omitir el-type d
y hacer:find . -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}
Finalmente, tenga en cuenta que si omite alguna acción (
-exec
es una acción), diga así:find . -name '.svn' -prune -o -name 'message.*'
entonces la
-print
acción está implícita pero se aplicará a la expresión ENTERA, incluida la-name '.svn' -prune -o
parte, y así imprimirá todos los directorios .svn, así como los archivos 'mensaje. *', que probablemente no sea lo que desea. Por lo tanto, siempre debe usar una 'acción' en el lado derecho de la expresión booleana cuando se usa-prune
de esta manera. Y cuando se imprime esa acción, debe agregarla explícitamente, así:find . -name '.svn' -prune -o -name 'message.*' -print
fuente
Pruebe findrepo, que es un contenedor simple alrededor de find / grep y mucho más rápido que ack. Lo usaría en este caso como:
fuente
wcfind
es un script de derivador de búsqueda que uso para eliminar automáticamente directorios .svn.fuente
Esto funciona para mí en el indicador de Unix
El comando anterior enumerará ARCHIVOS que no están con .svn y hará el grep que mencionó.
fuente
xxx.svnxxx
. Esto es importante: por ejemplo, si está usando git en lugar de svn, a menudo querrá incluir archivos como .gitignore (que no son metadatos, es un archivo normal que se incluye en el repositorio) en los resultados de find.Por lo general, canalizo la salida a través de grep una vez más eliminando .svn, en mi uso no es mucho más lento. ejemplo típico:
O
fuente