¿Cómo eliminar directorios basados ​​en la salida `find`?

148

Emito el siguiente comando para encontrar los directorios .svn:

find . -name ".svn"

Eso me da los siguientes resultados:

./toto/.svn
./toto/titi/.svn
./toto/tata/.svn

¿Cómo podría procesar todas estas líneas rm -frpara eliminar los directorios y su contenido?

Arnaud
fuente
3
GNU find tiene la -deleteopción.
Marco
55
O puede agregar -exec rm -r "{}" \;al final de la búsqueda: ¡tenga cuidado al usarlo rm -r! :)
Drav Sloan
10
@Marco La opción de eliminar no parece funcionar en los directorios.
Arnaud
@SuperChafouin Funciona perfectamente bien aquí en archivos y directorios. El punto es que solo elimina los directorios de emtpy y cuando lo especifica -name ".svn"solo coincide con el .svndirectorio en sí y no con los archivos ubicados en el .svndirectorio.
Marco
1
@SuperChafouin pero no funcionará para rutas con espacios en ellas (por lo tanto, -execcon comillas "{}").
Drav Sloan

Respuestas:

195

Buscar puede ejecutar argumentos con la -execopción para cada coincidencia que encuentre. Es un mecanismo recomendado porque puede manejar rutas con espacios / líneas nuevas y otros caracteres correctamente. Tendrá que eliminar el contenido del directorio antes de poder eliminar el directorio en sí, así que úselo -rcon el rmcomando para lograrlo.

Para su ejemplo, puede emitir:

find . -name ".svn" -exec rm -r "{}" \;

También puede decirle a find que solo busque directorios llamados .svn agregando un -type dcheque:

find . -name ".svn" -type d -exec rm -r "{}" \;

Advertencia Use rm -rcon precaución para eliminar la carpeta y todo su contenido.

Si desea eliminar solo directorios vacíos, así como directorios que contienen solo directorios vacíos, find puede hacerlo por sí mismo -deletey -empty:

find . -name ".svn" -type d -empty -delete
Drav Sloan
fuente
22
He visto consejos para siempre ejecutar -type después -name en los comandos de búsqueda, ya que las llamadas a statpara obtener el tipo son caras. Lo probé yo mismo en un grupo bastante grande de archivos, y parece ser cierto: la ejecución find . -name 'foo' -type dtomó 19 segundos, mientras que find . -type d -name 'foo'tomó 32 segundos. Entonces, aproximadamente un 50% más de tiempo para correr -typeprimero.
spinup
66
He estado usando este comando durante años, pero en Mac ahora recibo errores que dicen que esos directorios no existen. A pesar de que los elimina. Nunca vi mensajes antes.
chovy
1
Igual que @chovy. ¿Hay alguna forma de deshacerse de estos mensajes?
Clément
2
@chovy @ clément Eso se debe a que findquiere ver en esa carpeta otras coincidencias, mientras elimina la carpeta al mismo tiempo. ~ Todavía no sé cómo solucionar esto. ~ Solución sucia:find . -name "folder-to-delete" -print0 | xargs -r0 -- rm -r
Charlie
55
@chovy @ Clément Creo que el -depthargumento arregla esto:find . -depth -name ".svn" -type d -exec rm -r "{}" \;
gimboland
67

Aquí hay una portátil aún más rápida que la respuesta aceptada.

Usar un +punto y coma en lugar de punto y coma como findterminador de comando es optimizar el uso de la CPU. Eso puede ser significativo si tiene muchos .svnsubdirectorios:

find . -name .svn -type d -exec rm -rf {} +

Tenga en cuenta también que nunca 1 necesita citar las llaves aquí.

1 A menos que use el fishcaparazón.

jlliagre
fuente
55
¿Qué diferencia hay entre + y punto y coma? ¿Por qué no usamos llaves?
Shicheng Guo
1
@ShichengGuo Con el punto y coma, habrá un comando rm por directorio encontrado, con el comando + un solo rm procesará todos los directorios encontrados (o al menos un gran número de ellos). No recibo su segunda pregunta, rizado Los frenos se usan aquí.
jlliagre
Creo que @ShichengGuo significa por qué no necesitamos citar las llaves aquí (@jlliagre escribió que nunca necesitamos citarlas). No puedo encontrar una referencia ahora, pero entiendo que es porque find escapará automáticamente de las rutas reemplazadas por {}.
Quinn Commandado
La respuesta y la pregunta no son correctas sobre qué + hace. Si se encuentran muchos archivos, entonces ';' daría el error 'línea de comando demasiado larga'. + divide los archivos encontrados en lotes que son menores que la longitud máxima permitida de la línea de comando y ejecuta el comando para cada lote.
Gaoithe
1
@gaoithe Revertí la edición que reemplazó una declaración correcta por una incorrecta El uso de + no reducir el uso de la CPU, el uso de ; no dar lugar a un comando de error demasiado largo.
jlliagre
27

Suponga que está usando gnu find , puede usar la -deleteopción:

find . -name test -delete

que es más fácil de recordar

Chun Yang
fuente
Considere expandir su publicación con una explicación del comando (o documentación para respaldar su solución). A menudo, las respuestas de una (o dos) líneas no son las más esclarecedoras.
HalosGhost
94
Esto no funciona en directorios no vacíos.
belacqua
2
también funciona en Mac OS X
dibuje el
Esto no funciona para carpetas no vacías, pero es la solución más fácil y segura
RousseauAlexandre
El orden de opciones es muy importante, find las ejecutará en orden, así que -eliminar tiene que ser el último
Jose Ignacio Centeno
13

En mi computadora cuando uso:

find . \( -name dirname -type d \) -exec rm -r '{}' ';'

Los directorios se eliminan pero me sale el error:

find: ‘./dirname’: No such file or directory

para cada directorio

Mis directorios no están vacíos, por lo que la opción -delete no funcionará para mí. Encontré la razón de este comportamiento aquí :

  1. find toma (no necesariamente) la primera entrada en el directorio ./. esto sería, por ejemplo, dir.1 /
  2. lo compara con el patrón 'dir.?'. ¿coincide? si.
  3. find ejecuta "rm -r dir.1".
  4. find intenta ingresar dir.1 / para encontrar el patrón dentro del directorio. no sabe nada sobre el comando exec.
  5. ya no encuentra dir.1 / más. devuelve ENOENT (mira la salida de strace)

En su lugar, usé esto para evitar:

rm -r `find . -name dirname -type d`

Tenga en cuenta que find todavía intentará volver a aparecer en directorios llamados dirname, lo cual no es realmente necesario y tomará algo de tiempo adicional. Dependiendo de la estructura de su directorio, es posible que pueda solucionar esto con la --depthopción de búsqueda. Además, si tiene una estructura de directorio como dirname / foo / dirname, obtendrá errores de "No existe tal archivo o directorio" de rm. Para suprimir los errores, puede redirigir stderr a / dev / null o usar el -findicador (force) con rm.

Samuel
fuente
2
Mala idea: el nombre de archivo con espacios causará todo tipo de problemas horribles
Clément
2
Para futuros lectores: find . -name "to-delete" -print0 | xargs -r0 -- rm -res una versión a prueba de fallas que no se bloquea en los espacios
Charlie
3
Consulte unix.stackexchange.com/a/115869/8257 que necesita agregar -prune.
Mapio
1
Agregue -prunepara evitar el error "No existe tal archivo o directorio".
Julien Carsique
12

Una forma más rápida de hacer esto es:

find . -name ".svn" -type d -prune -exec rm -rf '{}' '+'

En caso de que tenga ".svn" dentro de otro ".svn".

Chang Yu-heng
fuente
Eso no es muy útil si desea encontrar los directorios para eliminar con los subdirectorios.
Alexis Wilke
5

Solución específica de Bash:

shopt -s globstar
rm -r **/.svn
shopt -u globstar #optional. this will disable globstar expansion
prisa
fuente
3
Nota para la expansión de la línea de comandos de globos que coinciden con muchos archivos, hay un límite para la cantidad de archivos que puede coincidir con este mecanismo. El pasar este límite dará lugar abash: /bin/rm: Argument list too long
Drav Sloan
1
@DravSloan es correcto, pero ese límite está en los cientos de miles de archivos. Es algo a tener en cuenta, pero probablemente no será un problema para la mayoría de las personas.
evilsoup
4

Descubrí que la -deleteacción funciona bien con la -pathprueba. Por ejemplo, lo siguiente debería funcionar en el problema de los carteles originales:

find . -path '*/.svn*' -delete
Magnus
fuente
¿Estás seguro? -deleteimplica -depth, y seguro elimina directorios no vacíos en mi sistema.
Magnus
Probado de nuevo y funciona. Tal vez fue solo un error tipográfico que he corregido.
kenorb
También probé este enfoque y funcionó: los directorios se eliminaron.
Allan