A menudo uso el findcomando 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 uinten múltiples messages.hy messages.cpparchivos:
# 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 findque ignore los .svndirectorios?
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
.svndirectorio en cada directorio de la copia de trabajo, las copias de trabajo de Subversion 1.7 tienen un solo.svndirectorio, 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 bifurcagreppara cada archivo, sino para un montón de archivos a la vez). Con este formulario también puede podar.svndirectorios sin usar la-pruneopción de buscar, es decirfind ... -print0 | egrep -v '/\.svn' | xargs -0 egrep ...-execwith+no forkgreppara cada archivo, mientras que usarlo con;does. Usar-execes en realidad más correcto que usarxargs. Tenga en cuenta que los comandos comolshacer algo, incluso si la lista de argumentos está vacía, mientras que los comandos comochmoddan 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 '{}' '+'.grepsalir.svnno es una buena idea también. Si bienfindestá especializado para manejar propiedades de archivos,grepno 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-prunepredicado defindfunciona 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
ackmucho, pero he encontrado que es sustancialmente más lento quefind -type f -name "*.[ch]" | xargs grepcuando se trata de una gran base de código.ackfactura como mejorgrep, no como fuente conscientefind? Algunos ejemplos de su uso para reemplazarfindharí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 -printporque 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-aesfalse, la segunda expresión no será evaluada (también llamada cortocircuito y evaluación ).-type dantes-name .svnes teóricamente más eficiente. Sin embargo, generalmente es insignificante, excepto si tiene un árbol de directorios muy grande.-printcomo 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 dantes de los dos-name, pero no vale la pena escribir más.Para ignorar
.svn,.gity otros directorios ocultos (comenzando con un punto), intente:Sin embargo, si el propósito de usar
findes 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
rgrepcomando incorporado de Emacs ignora el.svndirectorio, 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
findygreppatrones 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 \.svnfuente
.en la.svnexpresió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.svnexpresión regular.Crea un script llamado
~/bin/svnfind:Este script se comporta de manera idéntica a un
findcomando simple pero elimina.svndirectorios. De lo contrario, el comportamiento es idéntico.Ejemplo:
fuente
echocomando de búsqueda y decirme qué comando se ejecuta?svnfind -type ffunciona 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 ) -printSolo pensé que agregaría una alternativa simple a las publicaciones de Kaleb y de otros (que detalla el uso de la
find -pruneopciónack,repofindcomandos , 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 | xargsno se bifurcaegreppara 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 | xargsformulario, también puede usarlogreppara 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 configurarfindla-prunelógica).El
find | grep | xargsenfoque es similar afindla-regexopción de GNU (veaghostdog74la publicación de), pero es más portátil (también funcionará en plataformas donde GNUfindno está disponible).fuente
-execcambiofind: 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.findutilidad. Por favor vea la-execparte :-).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
-printestá 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' -pruneEsto 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-oque 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
.svnes 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 dy hacer:find . -name '.svn' -prune -o -name 'message.*' -exec grep -Iw uint {}Finalmente, tenga en cuenta que si omite alguna acción (
-execes una acción), diga así:find . -name '.svn' -prune -o -name 'message.*'entonces la
-printacción está implícita pero se aplicará a la expresión ENTERA, incluida la-name '.svn' -prune -oparte, 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-prunede esta manera. Y cuando se imprime esa acción, debe agregarla explícitamente, así:find . -name '.svn' -prune -o -name 'message.*' -printfuente
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
wcfindes 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