Удалить все каталоги из родительского каталога, кроме одного и его потомков

8

структура каталогов

Я хочу удалить каталог B и D. Но я хочу сохранить C и все его дочерние файлы и каталоги. Что такое команда для удаления всех дочерних каталогов родительского каталога, кроме одного каталога и его дочерних.

Помощь приветствуется.

Джо Саад
источник
каталоги, которые вы хотите удалить, пусты?
Старейшина Гик
Как насчет файлов, непосредственно расположенных в родительском каталоге ( Aв вашем примере)? Удалить их или оставить?
Byte Commander
Byte Commander спрашивает, есть ли файлы в A? или только каталоги? Вы хотите, чтобы обычные файлы в A удалялись или только каталоги?
Сергей Колодяжный

Ответы:

6

Что вы хотите, это команда:

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

Демо-версия:

# 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/

Объяснение:

  • find DIRECTORY команда call find для работы с DIRECTORY
  • -mindepth 1 : работать только с содержимым каталога, избегать самого каталога уровня 0
  • -maxdepth 1: предотвращает спуск в подкаталоги ( rm -rfв любом случае является рекурсивным, поэтому нам не нужно спускаться в подкаталоги для их удаления)
  • -type d : поиск только по каталогам
  • -not \( -name "keepMe" \) игнорировать элемент с именем, которое вы хотите сохранить
  • -exec rm -rf {} \; выполнить удаление на каждом найденном предмете
Сергей Колодяжный
источник
Отличное объяснение. Слишком много нажатий клавиш для меня, хотя ...
Старейшина Geek
1
findздесь хороший друг, но у Баша forи testесть лучшие друзья ...>: - D
Byte Commander
8

Использование расширенных функций glob оболочки bash (которые включены по умолчанию в текущих установках Ubuntu), учитывая

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

5 directories, 0 files

Вы можете обращаться ко всему, кроме Cего содержимого, используя выражение glob, A/!(C)т.е.

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

Таким образом, чтобы удалить все, кроме каталога Cи его содержимого, вы можете просто использовать

rm -rf A/!(C)

уход

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

3 directories, 0 files
steeldriver
источник
Удивительно узнать об этой функции. Он прекрасно работает после запуска ssh и запуска вручную, но я получаю `" -bash: строка 1: синтаксическая ошибка рядом с неожиданным токеном, ('"когда я запускаю его удаленно через ssh $VM_ADDRESS "rm -rf $APP_FOLDER/!(node_modules)". Любые идеи? Большое спасибо.
Ренато Гама
@renatoargh extglobопция оболочки доступна только для интерактивных оболочек - не уверен, сможете ли вы sshсделать это
принудительно
5

Одним из простых способов было бы использовать trash-cli

Вы можете установить его с sudo apt-get install trash-cli

После установки вы можете перейти в родительский каталог A с помощью, cd /Aа затем выполнить команду, trash B Dгде B и D - каталоги, которые вы хотите удалить (они попадут в корзину для диска, на котором они находятся, поэтому, если вы сделаете ошибку, вы можете восстановить файлы)

Протестировано под Ubuntu 16.04 и 14.04

Старейшина Гик
источник
Может ли это быть упрощено чем-то вроде trash ! C?
Сергей Колодяжный
@Serg Нету trash: cannot trash non existent ! '`
Старейшина Гик
@Serg и C разбиты ...
Старейшина Гик
Нашел его: stackoverflow.com/q/216995/3701431 Требует включения, extglobхотя.
Сергей Колодяжный
@Serg В зависимости от выполняемой работы это может быть весьма полезно! ;-)
Старейшина Гик
4

Просто используйте forцикл Bash и testотфильтруйте нужные каталоги, а rm -rfкоманду рекурсивно удалите каталоги, например:

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

Это перебирает все элементы (файлы и каталоги) внутри /path/to/parent/и рекурсивно удаляет элемент, если его имя не равноdir_survive . Если родительский каталог является текущим каталогом, вы можете писать только *как путь.

Если вы не уверены и хотите сначала проверить, какие элементы будут удалены без каких-либо действий, просто замените rm -rfв приведенной выше команде наecho и она выведет только кандидатов на удаление.

Вот пример запуска:

$ 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
источник