¿Cómo utilizar la opción '-prune' de 'buscar' en sh?
Pregunta
No entiendo muy bien el ejemplo dado por el man find
, ¿alguien puede darme algunos ejemplos y explicaciones?¿Puedo combinar expresiones regulares en él?
La pregunta más detallada es así:
Escribe un script de shell, changeall
, que tiene una interfaz como changeall [-r|-R] "string1" "string2"
.Encontrará todos los archivos con un sufijo de .h
, .C
, .cc
, o .cpp
y cambiar todas las apariciones de string1
a string2
. -r
Es una opción para permanecer solo en el directorio actual o incluir subdirectorios.
NOTA:
- Para el caso no recursivo,
ls
NO está permitido, solo podríamos usarfind
ysed
. - Lo intenté
find -depth
pero NO fue compatible.Por eso me preguntaba si-prune
podría ayudar, pero no entendí el ejemplo deman find
.
EDITAR2:Estaba haciendo una tarea, no hice preguntas detalladas porque me gustaría terminarla yo mismo.Como ya lo hice y lo entregué, ahora puedo plantear la pregunta completa.Además, logré terminar la tarea sin usar -prune
, pero me gustaría aprenderlo de todos modos.
Solución
De lo que había encontrado confuso -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 usar -prune
Es esto:
find [path] [conditions to prune] -prune -o \
[your usual conditions] [actions to perform]
Casi siempre quieres el -o
(lógico o) inmediatamente después -prune
, porque esa primera parte de la prueba (hasta e incluyendo -prune
) regresará falso por las cosas que realmente quieres (es decir: las cosas que no quiero podar).
Aquí hay un ejemplo:
find . -name .snapshot -prune -o -name '*.foo' -print
Esto encontrará los archivos "*.foo" que no están debajo ".snapshot" Directorios. En este ejemplo, -name .snapshot
constituye el [conditions to prune]
, y -name '*.foo' -print
es [your usual conditions]
y [actions to perform]
.
Notas importantes:
Si todo lo que desea hacer es imprimir los resultados que puede estar utilizado para dejar de lado el
-print
acción. Usted generalmente no quiero hacer eso cuando use-prune
.El comportamiento predeterminado de Find es "y" el completo expresión con el
-print
acción si no hay más acciones que-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 imprimirá el nombre del directorio que está podando, que generalmente no es lo que desea. En su lugar, es mejor especificar explícitamente el
-print
Acción si eso es lo que quieres:find . -name .snapshot -prune -o -name '*.foo' -print # DO THIS
Si su "condición habitual" coincide con los archivos que también coinciden con su condición de poda, esos archivos no ser incluido en la salida. La forma de arreglar esto es agregar un
-type d
predicarse a su condición de poda.Por ejemplo, supongamos que queríamos podar cualquier directorio que comenzara con
.git
(Esto es cierto que es algo artificial; normalmente solo necesita eliminar la cosa llamada exactamente.git
), pero aparte de eso quería ver todos los archivos, incluidos archivos como.gitignore
. Podrías probar esto:find . -name '.git*' -prune -o -type f -print # DON'T DO THIS
Esto serí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 adicional: si está utilizando la versión GNU de find
, la página Texinfo para find
tiene una explicación más detallada que su manualidad (como es cierto para la mayoría de las utilidades de GNU).
Otros consejos
Tenga cuidado de que -PRUNE no evite descender a ningún Directorio como algunos han dicho. Evita descender a directorios que coinciden con la prueba a la que se aplica. Quizás algunos ejemplos ayuden (vea la parte inferior para un ejemplo de regex). Perdón por que esto sea 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
Normalmente, la forma en que hacemos las cosas en Linux y la forma en que creemos que es de izquierda a derecha.
Entonces irías a escribir lo que estás buscando primero:
find / -name "*.php"
Entonces probablemente presione Enter y se dé cuenta de que está obteniendo demasiados archivos de los directorios que desea no. Excluyamos /medios para evitar buscar en sus unidades montadas.
Ahora debería agregar lo siguiente al comando anterior:
-print -o -path '/media' -prune
Entonces el comando final es:
find / -name "*.php" -print -o -path '/media' -prune
............... | <--- Incluya ---> | .................... | <- -------- excluir ---------> |
Creo que esta estructura es mucho más fácil y se correlaciona con el enfoque correcto.
Además del consejo dado en otras respuestas (no tengo representantes para crear respuestas) ...
Al combinar -prune
Con otras expresiones, hay una diferencia sutil en el comportamiento dependiendo de qué otras expresiones se usen.
El ejemplo de @Laurence Gonsalves encontrará los archivos "*.foo" que no están en ".snapshot" Directorios:-
find . -name .snapshot -prune -o -name '*.foo' -print
Sin embargo, esta mano corta ligeramente diferente, tal vez inadvertidamente, también enumerará el .snapshot
Directorio (y cualquier directorios .snapshot anidados):-
find . -name .snapshot -prune -o -name '*.foo'
La razón es (según la mano de obra en mi sistema):-
Si la expresión dada no contiene ninguna de las primarias -exec, -ls, -ok o -impresión, la expresión dada se reemplaza efectivamente por:
(ded_expression) -impresión
Es decir, el segundo ejemplo es el equivalente a ingresar lo siguiente, modificando así la agrupación de términos:-
find . \( -name .snapshot -prune -o -name '*.foo' \) -print
Esto al menos se ha visto en Solaris 5.10. Después de haber usado varios sabores de *nix durante aproximadamente 10 años, recientemente busqué una razón por la cual esto ocurre.
Prune es un no recurrir en ningún interruptor de directorio.
De la página del hombre
Si -nepth no se da, verdadero; Si el archivo es un directorio, no descienda a él. Si -nepth se da, falso; sin efecto.
Básicamente, no se desviará en ningún subtirectorio.
Tome este ejemplo:
Tienes los siguientes directorios
- /Inicio/Test2
- /Home/Test2/Test2
Si tu corres find -name test2
:
Devolverá ambos directorios
Si tu corres find -name test2 -prune
:
Volverá solamente/home/test2, ya que no descendería a/home/test2 para encontrar/home/test2/test2
No soy un experto en esto (y esta página fue muy útil junto con http://mywiki.wooledge.org/usingfind)
Me acabo de dar cuenta -path
es para un camino que coincide completamente con la cadena/ruta que viene justo después find
(.
en estos ejemplos) donde como como -name
coincide con todos los nombres de base.
find . -path ./.git -prune -o -name file -print
bloquea el directorio .git en su directorio actual ( Como tu hallazgo en .
)
find . -name .git -prune -o -name file -print
Bloquea todos los subdirectorios .git recursivamente.
Nota la ./
es extremadamente importante !! -path
debe coincidir con una ruta anclada con .
o lo que viene justo después de encontrar Si obtienes partidos sinlo (desde el otro lado del o '-o
') ¡Probablemente no haya podado! No era ingenuo de esto y me puso a usar el camino cuando es genial cuando no quieres podar todo el subdirectorio con el mismo nombre de base: D
Muestre todo, incluido el Dir en sí, pero no sus contenidos largos y aburridos:
find . -print -name dir -prune
Si lees todas las buenas respuestas aquí, ahora entiendo que las siguientes arrojan 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 llevará mucho más tiempo ya que todavía busca todo en el directorio 1.Supongo que la verdadera pregunta es cómo -or
resultados no deseados sin tener que buscarlos.
Así que supongo que podar significa no decentes los partidos pasados, sino marcarlos como hechos...
http://www.gnu.org/software/findutils/manual/html_mono/find.html"Sin embargo, esto no se debe al efecto de la acción '-poda' (que sólo evita un mayor descenso, no garantiza que ignoremos ese elemento).En cambio, este efecto se debe al uso de '-o'.Dado que el lado izquierdo de la condición "o" se realizó correctamente para ./src/emacs, no es necesario evaluar el lado derecho ("-print") para este archivo en particular".
find
Construye una lista de archivos. Aplica el predicado que suministró a cada uno y devuelve los que pasan.
Esta idea que -prune
Significa excluir de los resultados fue realmente confuso para mí. Puede excluir un archivo sin podar:
find -name 'bad_guy' -o -name 'good_guy' -print // good_guy
Todos -prune
lo hace es alterar el comportamiento de la búsqueda. Si la coincidencia actual es un directorio, dice "Oye find
, ese archivo que acaba de igualar, no desciendan a él ". Simplemente elimina ese árbol (pero no el archivo en sí) de la lista de archivos para buscar.
Debería ser nombrado -dont-descend
.