9

Недавно я столкнулся с задачей удаления всех файлов / папок в каталоге, кроме тех, которые соответствуют определенному шаблону. Поэтому я подготовил однострочную Unix-команду для выполнения этой работы. Это должна быть только одна строка? Полагаю, нет, но это определенно круче!

Хотя проблема довольно проста, я был немного удивлен тем, насколько сложным оказалось мое решение. Вот команда, которую я использовал; ПРИМЕЧАНИЕ: это плохое решение, потому что оно не обрабатывает имена файлов, содержащие символы перевода строки (что не имело значения в моей ситуации).

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

Я не использовал команду "найти", потому что я не хочу копировать в папки, соответствующие 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»).

Вопрос, есть ли лучшие (более элегантные и правильные) способы сделать это?


РЕДАКТИРОВАТЬ:
Недавно мне стало известно, что "найти" может быть лучшим вариантом:

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

Это решение правильно обрабатывает пути, содержащие символы перевода строки.

3 ответа3

9

Следующие примеры имеют префикс 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 :

# 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*))
7

Вот еще одно решение для find . Я не уверен, что это имеет какое-то реальное преимущество перед вашим, но оно не требует xargs и допускает редкую возможность, * расширяющуюся до слишком большого числа имен.

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

Я также добавил -type f чтобы он не пытался удалять каталоги.

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

0

Вместо этого вы можете использовать этот пример сценария реболя 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
]

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .