2009-09-28 5 views
161

No entiendo muy bien el ejemplo dado por el 'hombre encontrado', ¿alguien me puede dar algunos ejemplos y explicaciones? ¿Puedo combinar expresiones regulares en él?¿Cómo usar la opción '-rune' de 'buscar' en sh?


la pregunta más detallada es la siguiente:. Escribir un script de shell, changeall, que tiene una interfaz como "changeall [-r | -R] 'texto1' 'cadena2' Va a encontrar todos los archivos con una sufijo de .h, .C, .cc o .cpp y cambie todas las ocurrencias de "cadena1" a "cadena2". -r es una opción para permanecer en el directorio actual solamente o incluyendo el subdirectorio. NOTA: 1) para el caso no recursivo , 'ls' NO está permitido, solo pudimos usar 'find' y 'sed'. 2) Intenté 'find -depth' pero NO fue compatible. Por eso me preguntaba si '-prune' podría ayudar, pero no lo hice. 't entender el ejemplo de' hombre encontrar '.


EDI T2: estaba haciendo una tarea, no hice una pregunta con mucho detalle porque me gustaría terminarla yo mismo. Como ya lo hice y se lo entregué, ahora puedo formular toda la pregunta. Además, logré terminar la tarea sin usar -prune, pero me gustaría aprender de todos modos.

Respuesta

346

Lo Me pareció confuso acerca de -prune es que es una acción (como -print), no una prueba (como -name). Altera la lista de tareas pendientes, pero siempre devuelve verdadero.

El patrón general para el uso -prune es la siguiente:

find [path] [conditions to prune] -prune -o \ 
            [your usual conditions] [actions to perform] 

Más o menos, siempre quieren que la del -o inmediatamente después -prune, debido a que la primera parte de la prueba (hasta incluyendo -prune) devolverá falsa para las cosas que realmente quieres (es decir, las cosas que no quieres eliminar).

He aquí un ejemplo:

find . -name .snapshot -prune -o -name '*.foo' -print 

Este se encuentra el "*" .foo archivos que no están bajo directorios ".snapshot". En este ejemplo, -name .snapshot es la "prueba de las cosas que quiere podar", y -name '*.foo' -print es el "material que normalmente pondría después de la ruta".

Notas importantes:

  1. Si todo lo que quiere hacer es imprimir los resultados que podrían ser utilizados para dejar de lado la acción -print. Por lo general, no desea desea hacer eso cuando usa -prune.

    El comportamiento predeterminado del hallazgo es "y" el toda expresión con la acción -print si no hay acciones que no sean -prune (irónicamente) al final. Eso significa que escribir esto:

    find . -name .snapshot -prune -o -name '*.foo'    # DON'T DO THIS 
    

    es equivalente a escribir esto:

    find . \(-name .snapshot -prune -o -name '*.foo' \) -print # DON'T DO THIS 
    

    lo que significa que también se va a imprimir el nombre del directorio que está poda, que por lo general no es Lo que quieras. En su lugar, es mejor especificar explícitamente la acción -print si eso es lo que quiere:

    find . -name .snapshot -prune -o -name '*.foo' -print  # DO THIS 
    
  2. Si su "estado normal" pasa a coincidir con los archivos que también responden a su condición de ciruela pasa, esos archivos no se incluirán en el salida. La forma de solucionar esto es agregar un predicado -type d a su condición de poda.

    Por ejemplo, supongamos que queríamos podar cualquier directorio que se inició con .git (esto es cierto tanto artificial - normalmente sólo es necesario para eliminar cosa nombrada exactamente.git), pero aparte de eso quería ver todos los archivos , incluidos archivos como .gitignore. Es posible que intente esto:

    find . -name '.git*' -prune -o -type f -print    # DON'T DO THIS 
    

    Esto habría no incluir .gitignore en la salida.Aquí está la versión fija:

    find . -type d -name '.git*' -prune -o -type f -print  # DO THIS 
    

Consejo extra: si está utilizando la versión GNU de find, la página textinfo para find tiene una explicación más detallada de su página de manual (como es cierto para la mayoría de las utilidades GNU)

+6

no es 100% obvio en su texto (pero como usted solo imprime '* .foo' no está en conflicto) pero la parte de prun no imprime nada (no solo directorios) llamado ".snapshot". es decir, '-prune' no solo funciona en directorios (pero, para los directorios, también evita que entren los directorios que coinciden con esa condición, es decir, aquí los directorios que coinciden con' -name .snapshot'). –

+5

y +1 para usted por la explicación bien hecha (y especialmente la nota importante).Debes enviar esto a los desarrolladores de find (ya que la página de manual no explica "ciruela" para seres humanos normales ^^ Me costó muchos intentos averiguarlo, y no vi ese efecto secundario del que nos advertiste) –

+1

@OlivierDulac Ese es un muy buen punto acerca de los posibles archivos de extracción que desea conservar. He actualizado la respuesta para aclarar esto. en realidad, no es el propio '-prune' el que causa esto, por cierto. El problema es que el operador o "cortocircuitos", o tiene una precedencia menor que y. El resultado final es que si se encuentra un archivo llamado '.snapshot', coincidirá con el primer' -name', '-prune' no hará nada (pero devuelve true), y luego el o devuelve true desde su argumento de la izquierda era verdad. La acción (por ejemplo: '-print') es parte de su segundo argumento, por lo que nunca tiene posibilidad de ejecución. –

3

Prune es un no recurse en cualquier cambio de directorio.

Desde la página del

Si -depth no se da, es cierto; si el archivo es un directorio, no descienda a él. Si -depth es dado, falso; sin efecto.

Básicamente no se descompone en ningún subdirectorio.

Tome este ejemplo:

Usted tiene los siguientes directorios

  • /home/test2
  • /home/test2/test2

Si ejecuta find -name test2:

Se volverá ambos directorios

Si ejecuta find -name test2 -prune:

se devolverá solo/home/test2 ya que no descenderá en/home/test2 para encontrar/home/test2/test2

+0

no es 100% verdad: se trata de "hacer la poda a la coincidencia de condiciones, y si se trata de un directorio, lo saca de la tarea pendiente lista, es decir, no ingrese también ". -prune también funciona en archivos. –

24

Tenga en cuenta que -prune no impide descender a cualquier directorio como algunos han dicho. Impide descender a directorios que coincidan con la prueba a la que se aplica. Tal vez algunos ejemplos lo ayuden (vea la parte inferior para ver un ejemplo de expresiones regulares). Perdón por ser tan largo.

$ find . -printf "%y %p\n" # print the file type the first time FYI 
d . 
f ./test 
d ./dir1 
d ./dir1/test 
f ./dir1/test/file 
f ./dir1/test/test 
d ./dir1/scripts 
f ./dir1/scripts/myscript.pl 
f ./dir1/scripts/myscript.sh 
f ./dir1/scripts/myscript.py 
d ./dir2 
d ./dir2/test 
f ./dir2/test/file 
f ./dir2/test/myscript.pl 
f ./dir2/test/myscript.sh 

$ find . -name test 
./test 
./dir1/test 
./dir1/test/test 
./dir2/test 

$ find . -prune 
. 

$ find . -name test -prune 
./test 
./dir1/test 
./dir2/test 

$ find . -name test -prune -o -print 
. 
./dir1 
./dir1/scripts 
./dir1/scripts/myscript.pl 
./dir1/scripts/myscript.sh 
./dir1/scripts/myscript.py 
./dir2 

$ find . -regex ".*/my.*p.$" 
./dir1/scripts/myscript.pl 
./dir1/scripts/myscript.py 
./dir2/test/myscript.pl 

$ find . -name test -prune -regex ".*/my.*p.$" 
(no results) 

$ find . -name test -prune -o -regex ".*/my.*p.$" 
./test 
./dir1/test 
./dir1/scripts/myscript.pl 
./dir1/scripts/myscript.py 
./dir2/test 

$ find . -regex ".*/my.*p.$" -a -not -regex ".*test.*" 
./dir1/scripts/myscript.pl 
./dir1/scripts/myscript.py 

$ find . -not -regex ".*test.*"     . 
./dir1 
./dir1/scripts 
./dir1/scripts/myscript.pl 
./dir1/scripts/myscript.sh 
./dir1/scripts/myscript.py 
./dir2 
+0

si también "toca ./dir1/scripts/test" (es decir, tiene un archivo de "prueba", y no dir, en ese subdirector impreso), no se imprimirá por 'encontrar. -name test -prune -o -print': iow, '-prune' es una acción que también funciona en los archivos –

7

Agregando a los consejos dados en otras respuestas (no tengo representante para crear respuestas) ...

Al combinar -prune con otras expresiones, hay una sutil diferencia en el comportamiento dependiendo de qué otras expresiones son usados.

ejemplo @Laurence Gonsalves se encuentra el "*" .foo archivos que no están bajo directorios ".snapshot": -

find . -name .snapshot -prune -o -name '*.foo' -print 

Sin embargo, esta ligeramente diferente taquigrafía voluntad, quizá sin darse cuenta, también listar el directorio .snapshot (y los directorios anidados .snapshot): -

find . -name .snapshot -prune -o -name '*.foo' 

la razón es (de acuerdo con la página de manual en mi sistema): -

Si la expresión dada no contiene ninguna de las primarias -exec, -ls, -ok, o -print, la expresión dada se sustituye eficazmente por:

(given_expression) -print

es decir, el segundo ejemplo es el equivalente de entrar en el siguiente, modificando de este modo la agrupación de términos: -

find . \(-name .snapshot -prune -o -name '*.foo' \) -print 

Este al menos se ha visto en Solaris 5,10. Habiendo usado varios sabores de * nix por aproximadamente 10 años, solo recientemente he buscado una razón por la que esto ocurre.

20

Normalmente, la forma nativa en que hacemos las cosas en Linux y la forma en que pensamos es de izquierda a derecha.
Así que va a ir y escribir lo que busca en primer lugar:

find/-name "*.php" 

Entonces es probable que pulsa enter y darse cuenta de que está recibiendo demasiados archivos de directorios usted no desea. Excluyamos/medios para evitar buscar en las unidades montadas.
Ahora debería simplemente añada lo siguiente a la orden anterior:

-print -o -path '/media' -prune 

por lo que el último comando es:

find/-name "*.php" -print -o -path '/media' -prune 

...............| < --- Incluir ---> | .................... | < ---------- Excluir ---------> |

Creo que esta estructura es mucho más fácil y se correlaciona con el enfoque correcto

+3

No esperaba que esto fuera eficiente. Pensé que evaluaría primero la cláusula de la izquierda antes de la pode, pero para mi sorpresa una prueba rápida parece sugerir que 'find' es lo suficientemente inteligente como para procesar la cláusula' -prune' primero. Hmmm, interesante. – artfulrobot

+0

¡Nunca lo había considerado así en casi una década de usar GNU find! ¡Gracias por eso! Definitivamente cambiará la forma en que pienso sobre '-prune' a partir de ahora. –

+0

@artfulrobot ¿Realmente lo está procesando primero? Pensé que estaba ingresando '/ media', notando que no se llama' * .php' y luego verificando si está actualmente dentro de '/ media', viendo que está y por lo tanto omitiendo ese subárbol completo. Sigue siendo de izquierda a derecha, simplemente no hace ninguna diferencia siempre que ambos controles no se superpongan. – phk

2

no soy un experto en esto (y esta página es muy útil junto con http://mywiki.wooledge.org/UsingFind)

di cuenta -path es un camino que coincide totalmente con la cadena/ruta que viene justo después de find (. en estos ejemplos) donde -name coincide con todos los elementos básicos.

find . -path ./.git -prune -o -name file -print 

bloquea el directorio .git en el directorio actual ( como su hallazgo en .)

find . -name .git -prune -o -name file -print 

bloquea todos los subdirectorios .git de forma recursiva.

¡Observe que el ./ es extremadamente importante! -path debe coincidir con un camino anclado a .o lo que venga después de encontrar si obtiene coincidencias sin él (del otro lado de o de '-o') ¡probablemente no se haya podado! Yo era ingenuamente inconsciente de esto y me puse de usar -path cuando es genial cuando no quieres podar todos los subdirectorios con el mismo nombre base: D

+0

Nota: si dices 'encontrar bla /', entonces necesitarías -path 'bla /' .git (o si empujaste un '*' al frente, se comportaría más como -name) – sabgenton

0

Si has leído todas las buenas respuestas aquí, mi comprensión ahora es que el siguiente devolverán los mismos resultados:

find . -path ./dir1\* -prune -o -print 

find . -path ./dir1 -prune -o -print 

find . -path ./dir1\* -o -print 
#look no prune at all! 

Pero el último tomará mucho más tiempo, ya que aún busca a cabo todo en dir1. Supongo que la verdadera pregunta es cómo sacar -or los resultados no deseados sin realmente buscarlos.

así que supongo que los medios hacen de ciruela partidos pasados ​​no decente, pero marcarla como hecha ...

http://www.gnu.org/software/findutils/manual/html_mono/find.html "Sin embargo, esto no se debe al efecto de la acción '-prune' (que sólo evita mayores descenso, no se asegura de que ignoremos ese elemento). En cambio, este efecto se debe al uso de '-o'. Dado que el lado izquierdo de la condición "o" ha tenido éxito para ./src/emacs, no es necesario evaluar el lado derecho ('-print') en absoluto para este archivo en particular ".

1

mostrar todo lo que incluye dir sí, pero no sus largas contenidos aburrido:

find . -print -name dir -prune 
Cuestiones relacionadas