¿Cómo elimino todos los subdirectorios de un directorio?

51

Esta pregunta es una especie de fase II de la primera pregunta que publiqué aquí

Tengo un directorio que contiene un montón de subdirectorios, archivos .zip y otros archivos aleatorios que no están incluidos en un subdirectorio.

Me gustaría que un script de línea de comando elimine todos los subdirectorios del directorio principal, pero mantenga todos los archivos zip y los archivos sueltos que no pertenecen a ningún subdirectorio. Todos los subdirectorios tienen contenido, así que creo que necesitaría forzar su eliminación con el comando -f.

Básicamente, un comando que mira dentro del directorio principal (o el directorio actual) elimina todas las carpetas de él, pero mantiene el resto del contenido y los archivos que no son una carpeta o están contenidos dentro de una carpeta.

Entiendo que eliminar elementos de la línea de comandos requiere un cuidado especial, pero ya he tomado todas las precauciones necesarias para realizar copias de seguridad de forma remota.

Evster
fuente

Respuestas:

62

En BASH puede usar la barra diagonal final ( creo que debería funcionar en cualquier shell POSIX):

rm -R -- */

Tenga en cuenta lo --que separa las opciones de los argumentos y le permite a uno eliminar entradas que comienzan con un guión; de lo contrario, después de la expansión por el shell, el nombre de la entrada se interpretará como una opción por rm(lo mismo vale para muchas otras utilidades de línea de comandos).

Agregue la -fopción si no desea que se le solicite confirmación al eliminar archivos que no se pueden escribir.

Tenga en cuenta que, de forma predeterminada, los directorios ocultos (aquellos cuyo nombre comienza con .) se dejarán solos.

Una advertencia importante: la expansión de */también incluirá enlaces simbólicos que eventualmente se resolverán en archivos de tipo directorio . Y dependiendo de la rmimplementación, rm -R -- thelink/simplemente eliminará el enlace simbólico o (en la mayoría de ellos) eliminará el contenido del directorio vinculado de forma recursiva, pero no ese directorio ni el enlace simbólico.

Si se usa zsh, un mejor enfoque sería usar un calificador global para seleccionar solo archivos de tipo directorio:

rm -R -- *(/) # or *(D/) to include hidden ones

o:

rm -R -- *(-/)

para incluir enlaces simbólicos a directorios (pero debido a que, esta vez, la expansión no tiene /s finales , solo el enlace simbólico se elimina con todas las rmimplementaciones).

Con bashAT&T ksh, yasho zshpuedes hacer:

set -- */
rm -R -- "${@%/}"

para quitar el rastro /.

Peterph
fuente
¡Hermosa! Esto funciona perfectamente No me di cuenta de que era tan fácil de hacer. ¿Te importaría elaborar sobre -r vs. -R y qué hacen esos comandos? Muchas gracias.
Evster
-r, -R, --recursiveSon sinónimos que significa "quitar y directorios de forma recursiva su contenido".
Peter
¿Puedes explicar qué - y * / hacer?
anfibio
66
También puede decir rm -R ./*/: también evita problemas con los nombres de guiones.
l0b0
1
Solo tenga cuidado de no cambiar el orden de * y /. rm -R - / * hace algo totalmente diferente que quizás no quieras que suceda: |
ChrisOdney
13

Además de la forma de comodín, también puede usar find(al menos GNU find) para hacer esto:

find -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 rm -R

Al igual que con otras findlíneas, puede ejecutar la primera parte ( find -mindepth 1 -maxdepth 1 -type d) para ver una lista de directorios que se eliminarán.

Una opción más segura es hacer algo como esto:

find -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 mv -i -t ../to-rm
# or
mv -i -t ../to-rm */
# or
mv -i */ ../to-rm

cualquiera de los cuales moverá todas las cosas en ../to-rmlugar de eliminarlas. Puede verificar que hizo lo que quería, rm -Rfese directorio en su tiempo libre.

derobert
fuente
+1 para el "CLI-Trash bin" to-rmy findque maneja muy bien los directorios que comienzan con un punto (además de cualquier otro escape engorroso). :)
Peter
Gracias por el consejo. Me gusta la idea de moverme a un directorio separado antes de eliminar. Estoy trabajando a través de Terminal en Mac OS X, y creo que necesitaría instalar algún tipo de paquete GNU para usar los comandos -mindepth y -maxdepth, ¿correcto?
Evster
@Evster no está seguro si Mac OS X find es compatible con esos. Supongo que Fink (¿todavía está ahí?) Podría instalar un hallazgo que sí. O puede omitirlos y luego filtrar la lista de archivos producidos usando grep. Definitivamente use la opción mv en eso, en lugar de rm.
derobert
4

Es posible que desee crear un script para algunas de estas sugerencias, especialmente rm -R -- */, y mantenerlo en su carpeta / usr / local / bin; o cree uno aliasen su archivo ~ / .bashrc. Dado que es muy fácil escribir mal un comando y romper su sistema, incluso una sola letra y / o el orden de las letras puede tener consecuencias catastróficas, esto serviría como una solución algo más sólida que tener que escribir las diferentes opciones y argumentos cada vez que quieras realizar esta tarea.

Además, es posible que desee incluir la opción -i or --interactive=onceu -I or --interactive=alwaysen su secuencia de comandos / comando que servirá como otra herramienta para evitar las eliminaciones no deseadas.

Además, algo como derobert sugirió que sería lo mejor; simplemente copie / pegue el script en un editor de archivos / terminales y ajústelo a sus necesidades específicas, y los archivos / directorios se moverán a un solo directorio (cuyo contenido puede verificar / verificar) que simplemente puede eliminar mediante emitiendo el rm -rfcomando.

Otra opción es utilizar una aplicación GUI, como su administrador de archivos, y simplemente seleccionar todos los archivos / carpetas aplicables que desea eliminar. Consulte las páginas del manual de su distribución si no tiene permisos.

Finalmente, si las carpetas están vacías, esencialmente nombres de archivo simples, puede usar el rmdircomando para eliminarlas. No funciona para todo lo que desee eliminar, pero será útil en ocasiones cuando desee realizar una "limpieza de la casa". ** Es posible que desee probar la -p --ignore-fail-on-non-emptyopción, que le permitirá eliminar ciertos subdirectorios, así como sus "padres" vacíos, los directorios en los que residen.

ILMostro_7
fuente
Esa es una muy buena idea para crear un script separado que pueda llamar para este comando. ¿Puede explicar qué hacen exactamente las opciones -i e -I? ¡Gracias!
Evster
-I opción le preguntará una vez después de presionar "Enter" para confirmar que desea eliminar esto (cuando hay más de 3 archivos / carpetas "seleccionados"); mientras que la opción -i emitirá un mensaje para cada archivo, en el que puede confirmar simplemente tocando "y" y "Enter"; cualquier otra cosa que no sea una respuesta afirmativa hará que ese archivo específico se omita durante el proceso de eliminación.
ILMostro_7
1

Primero debe enumerar los directorios y luego eliminarlos, sin obstaculizar los archivos normales, ls -d * /, solo enumera los subdirectorios, y al canalizarlos con rm se eliminan los directorios y el contenido, manteniendo intactos los archivos sueltos.

Este comando debería hacer el trabajo,

ls -d  */ | xargs rm -rf
Ankit Marothi
fuente
1
¿Cuál sería el beneficio rm -rf -- */? printf '%s\0' */ | xargs -r0 rm -rf --ayudaría (en shells donde printfestá integrado y no ls) a evitar errores de listas demasiado grandes , pero ls -d */ | xargs rm -rfno agrega nada AFAICT excepto problemas adicionales.
Stéphane Chazelas
1
@AnthonyGeoghegan, sí, por ejemplo, si hubiera un directorio llamado " .."(espacio ..), eliminaría el contenido del directorio principal con algunas lsimplementaciones. Y no son solo espacios, también son otros caracteres en blanco, nueva línea, comillas simples, comillas dobles, barras invertidas y nombres de archivos que comienzan con -.
Stéphane Chazelas
2
@Ankit, puedes comenzar con mywiki.wooledge.org/ParsingLs
Stéphane Chazelas
1
Cuando comprenda completamente la sugerencia de @ StéphaneChazelas de usar printfpara generar una lista donde cada nombre es terminado por el carácter nulo para que pueda procesarse xargscon la -0opción, le aconsejo que edite su respuesta para actualizarla con su variación. Estaría bastante seguro de que él estaría feliz de que use su fragmento de código si lo entiende y ha aprendido cómo protege contra el comportamiento indeseable causado por ciertos nombres de archivo que podrían existir.
Anthony G - justicia para Mónica
1
El uso xargstiene una ventaja sobre la respuesta aceptada (funciona cuando hay una gran cantidad de archivos / directorios en el directorio actual), por lo que hay margen para editar esto en una respuesta útil. Personalmente, he encontrado que responder a las preguntas de Stack Exchange es una buena experiencia de aprendizaje, especialmente cuando recibo comentarios útiles de otros usuarios.
Anthony G - justicia para Mónica
-1

rm -rf <directory name>. Funciona. Simplemente escribir rm <directory name>solo conduce a una cantidad de subpreguntas en las que cada uno de los subdirectorios debe eliminarse manualmente. Pero, rm -rfayuda a eliminar todo el directorio junto con sus subdirectorios a la vez.

Riya Melvin
fuente
55
El OP solicitó mantener el contenido del directorio actual.
Stephen Rauch