Unix - видалення файлів і папок, крім PATTERN


10

Нещодавно перед нами стояло завдання видалити всі файли / папки в каталозі, виключаючи ті, що відповідають певній схемі. Тому я підготував однорядну команду unix для виконання роботи. Повинен бути лише один рядок? Я гадаю, ні, але точно так крутіше!

Хоча проблема досить проста, я трохи здивувався тому, наскільки складним було моє рішення. Ось команда, яку я використав; ПРИМІТКА. Це неправильне рішення, оскільки воно не обробляє назви файлів, що містять символи подачі рядків (що в моїй ситуації не мало значення).

ls | grep -v PATTERN | xargs -n1 -IREPLACE rm -rf REPLACE

Я не використовував команду "find", тому що не хочу повторювати папки, що відповідають PATTERN. Наприклад, розглянемо таку структуру файлів:

file_foo.txt
first_dir
  |
  +--> contents
  +--> ...
foo_dir
  |
  +--> anotherfile.txt
  +--> morefiles.log
foo_file.txt
somefile.txt

Використовуючи шаблон "foo", потрібно видалити лише "first_dir" (і це, звичайно, вміст) та "somefile.txt" (а не "Anotherfile.txt" або "morefiles.log").

Запитання, чи є кращі (більш елегантні та правильні) способи цього досягти?


EDIT:
Нещодавно мені було звернено увагу, що "знайти" може бути кращим варіантом:

find * -maxdepth 0 ! -name PATTERN -print0 | xargs -0n1 rm -rf

Це рішення правильно обробляє контури, що містять символи подачі рядків.


EDIT: змінив помилковий "the_dir" на виправлення "first_dir".
joxl

Відповіді:


10

Наступні приклади мають echoпрефікс, щоб ви могли протестувати шаблони, перш ніж їх реально використовувати. Видаліть, echoщоб активувати rm -rf. Замініть rm -riзапит на підтвердження.

ksh має розширення з негативною відповідністю до свого глобусу:

# ksh
echo rm -rf !(*foo*)

Той самий синтаксис є в bash, якщо встановити extglobпараметр:

# bash
shopt -s extglob
echo rm -rf !(*foo*)

zsh має для цього свій синтаксис:

# zsh
setopt extended_glob
echo rm -rf ^*foo*

Він також може використовувати синтаксис ksh -style:

# zsh: ksh-style glob syntax
setopt ksh_glob no_bare_glob_qual
echo rm -rf !(*foo*)

# zsh: ksh-style glob syntax, adapted for the default bare_glob_qual option
setopt ksh_glob bare_glob_qual
echo rm -rf (!(*foo*))

Простий, елегантний, обробляє символи, що передаються з лінією, (майже) один рядок (я додав shopt -s extglobу свій файл .bashrc, тому тепер це однолінійний). Ідеально! Обіцяю прийняти рішення, як тільки моя репутація це дозволить.
joxl

7

Ось ще одне findрішення. Я не впевнений, що це має якусь реальну перевагу перед вашою, але вона не потребує xargsі допускає рідкісну можливість, що * розширюється на занадто багато імен.

find . -maxdepth 1 ! -name PATTERN -type f -delete

Я також додав, -type fщоб він не намагався видалити каталоги.

Попередження: -deleteпотужно. Я дав одному з моїх тестових файлів 0 дозволів, і команда вище видалила його без вагань.


6
Перевірте спочатку. Замінити -deleteз , -printщоб побачити , якщо це знайти файли , які ви хотіли. Якщо все добре, використовуйте історію команд (наприклад, натисніть кнопку вгору), щоб повернутися до попередньої команди, щоб переконатися, що ви працюєте з тими ж фільтрами пошуку.
Дуг Харріс

Читайте уважно, зверніть увагу , що я зробити бажання видалити каталоги. І find -deleteне видалятиме непорожні каталоги. Також зауважте, що find -maxdepth 1збіги "". (поточний каталог), що дійсно погано. Хоча мені подобається ваша ідея усунення xargs, можна використати find -execальтернативно. find * -maxdepth 0 ! -name PATTERN -exec rm -rf '{}' \;
joxl

0

Ви можете використовувати цей приклад сценарію rebol http://askcodegeneration.com/keep-subversion/ замість цього набагато зрозуміліше, яке може керувати взаємодією користувачів, як вибір та підтвердження папок:

delete-file: func[file][
    if/else none? find file "/.svn/" [
        delete file
    ][
        print ["keeping" file]
    ]
]
dir: request-dir
ans: ask rejoin ["Do you confirm " dir "? (Yes): "]
if (ans = "Yes") [
    foreach-file dir :delete-file
]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.