Eliminar todos los directorios de un directorio principal, excepto uno y sus descendientes

8

estructura de directorios

Quiero eliminar el directorio B y D. Pero quiero mantener C y todos sus archivos y directorios descendientes. ¿Cuál es el comando para eliminar todos los directorios hijos de un directorio padre, excepto un directorio y sus hijos?

Ayuda apreciada.

Joe Saad
fuente
¿Están vacíos los directorios que desea eliminar?
Élder Geek
¿Qué pasa con los archivos ubicados directamente en el directorio principal ( Aen su ejemplo)? ¿Eliminarlos también o conservarlos?
Byte Commander
Lo que Byte Commander pregunta es, ¿hay algún archivo en A? o solo directorios? ¿Desea archivos regulares en A eliminado o solo directorios?
Sergiy Kolodyazhnyy

Respuestas:

6

Lo que quieres es este comando:

find ~/TESTDIR -mindepth 1 -maxdepth 1 -type d -not \( -name "keepMe" \) -exec rm -rf {} \;

Manifestación:

# List what's inside directory we want to remove
$ ls
file1  file2  keepMe/  removeA/  removeB/
# Testing what find gives without removing
$ find ~/TESTDIR -mindepth 1 -type d -not \( -name "keepMe" \)               
/home/xieerqi/TESTDIR/removeA
/home/xieerqi/TESTDIR/removeB
# Actual removal and testls
$ find ~/TESTDIR -mindepth 1 -maxdepth 1 -type d -not \( -name "keepMe" \) -exec rm -rf {} \;
$ ls
file1  file2  keepMe/

Explicación:

  • find DIRECTORY llame al comando find para operar en el DIRECTORIO
  • -mindepth 1 : trabaje solo con el contenido del directorio, evite el directorio en sí mismo que es el nivel 0
  • -maxdepth 1: evita descender a subdirectorios (de rm -rftodos modos es recursivo, por lo que no necesitamos descender a subdirectorios para eliminarlos)
  • -type d : busca solo directorios
  • -not \( -name "keepMe" \) ignore el elemento con el nombre que desea conservar
  • -exec rm -rf {} \; realizar la eliminación de cada elemento encontrado
Sergiy Kolodyazhnyy
fuente
Gran explicación Demasiadas pulsaciones de teclas para mí, sin embargo ...
Élder Geek
1
findes un buen amigo aquí, pero Bash fory testson mejores amigos ...>: - D
Byte Commander
8

Uso de las funciones de glob extendido del shell bash (que están habilitadas por defecto en las instalaciones actuales de Ubuntu)

$ tree A
A
├── B
├── C
│   ├── ac1
│   └── ac2
└── D

5 directories, 0 files

puede abordar todo, excepto Csus contenidos, utilizando la expresión global, A/!(C)es decir

$ echo A/!(C)
A/B A/D

Entonces, para eliminar todo excepto el directorio Cy su contenido, simplemente puede usar

rm -rf A/!(C)

dejando

$ tree A
A
└── C
    ├── ac1
    └── ac2

3 directories, 0 files
conductor de acero
fuente
Es sorprendente saber acerca de esta característica. Funciona muy bien después de ejecutar ssh y ejecutarlo manualmente, pero aparece "" -bash: línea 1: error de sintaxis cerca de un token inesperado ('"cuando lo ejecuto de forma remota ssh $VM_ADDRESS "rm -rf $APP_FOLDER/!(node_modules)". ¿Alguna idea? Muchas gracias.
Renato Gama
@renatoargh la extglobopción del shell sólo se habilita para las cáscaras interactivas - no estoy seguro si se puede obligar ssha hacer eso
steeldriver
5

Una manera fácil sería usar trash-cli

puedes instalarlo con sudo apt-get install trash-cli

una vez instalado, puede navegar al directorio principal A con cd /Ay luego emitir el comando trash B Ddonde B y D son los directorios que desea eliminar (terminarán en la papelera de la unidad en la que se encuentran, por lo que si comete un error puede recuperar los archivos)

Probado en Ubuntu 16.04 y 14.04

Elder Geek
fuente
¿Podría esto simplificarse con algo así trash ! C?
Sergiy Kolodyazhnyy
@Serg Nope trash: cannot trash non existent ! ''
Elder Geek
@Serg y C se destrozan ...
Elder Geek
Lo encontré: stackoverflow.com/q/216995/3701431 Sin extglobembargo, requiere habilitarlo .
Sergiy Kolodyazhnyy
@Serg Dependiendo del trabajo en cuestión, ¡eso podría ser bastante útil! ;-)
Élder Geek
4

Simplemente use el forbucle de Bash y testpara filtrar los directorios deseados y el rm -rfcomando para eliminar directorios de forma recursiva, así:

for x in /path/to/parent/*; do test "$x" != "dir_survive" && rm -rf "$x"; done

Esto itera sobre todos los elementos (archivos y directorios) dentro /path/to/parent/y elimina el elemento de forma recursiva si su nombre no es igual a dir_survive. Si el directorio principal es el directorio actual, solo puede escribir *como ruta.

Si no está seguro y quiere probar qué elementos se eliminarían primero sin realizar ninguna acción, simplemente reemplace rm -rfel comando anterior con echoy solo generará los candidatos de eliminación.

Aquí hay un ejemplo de ejecución:

$ tree
.
├── dir1
│   ├── subdir1
│   │   ├── file1
│   │   └── file2
│   └── subdir2
│       ├── file1
│       └── file2
├── dir2
│   ├── subdir1
│   │   ├── file1
│   │   └── file2
│   └── subdir2
│       ├── file1
│       └── file2
└── dir_survive
    ├── subdir1
    │   ├── file1
    │   └── file2
    └── subdir2
        ├── file1
        └── file2

9 directories, 12 files

$ for x in *; do test "$x" != "dir_survive" && rm -rf "$x"; done

$ tree
.
└── dir_survive
    ├── subdir1
    │   ├── file1
    │   └── file2
    └── subdir2
        ├── file1
        └── file2

3 directories, 4 files
Byte Commander
fuente