Удалить все, кроме одного (или нескольких) типов файлов

20

Я пытался найти команду для удаления всех файлов в папке, но не какой-то тип файла. Но мне, кажется, не повезло. Что я пробовал до сих пор:

set extended_glob
rm !(*.dmg)
# this returns zsh:number expected

rm ./^*.dmg
# this returns no matches found 

Я использую версию zsh zsh 5.0.2 (x86_64-apple-darwin13.0.1).

Джунг Нгуен
источник

Ответы:

22

extended_globВариант дает вам ЗШ свой собственный расширенный синтаксис Глоб .

setopt extended_glob
rm -- ^*.dmg
rm -- ^*.(dmg|txt)

Вы можете установить ksh_globопцию, чтобы получить ksh globs . Помните, что в общем случае, когда отрицательный шаблон является последним в слове, zsh может анализировать скобки как квалификаторы glob (это не происходит в режиме эмуляции ksh).

setopt ksh_glob
rm -- !(*.dmg|*.txt)
setopt no_bare_glob_qual
rm -- !(*.dmg)
Жиль "ТАК - перестать быть злым
источник
Это не похоже на работу. Когда я бегу, rm -r secrets/!(directory)он продолжает спрашивать, number expectedа иногда и даетevent not found: directory
CMCDragonkai
@CMCDragonkai «ожидаемое число» означает, что вы не установили ksh_globопцию. «Событие не найдено: каталог» означает, что вы используете bash (который также понимает !(…)синтаксис, но только после shopt -s extglob).
Жиль "ТАК - перестань быть злым"
Как я мог запустить bash, когда был в моей оболочке zsh?
CMCDragonkai
Для меня setopt ksh_glob; echo !(a|b)работает, пока setopt ksh_glob; echo !(a)не работает («ожидаемое число») ...
ThiefMaster
@ThiefMaster У меня была такая же проблема. Это ошибка?
CodeTower
5

Вы можете использовать findвместо своей оболочки:

find . -mindepth 1 -maxdepth 1 ! -name "*.dmg" -delete

От man find:

   ! expr True  if  expr  is false.  This character will also usually need
          protection from interpretation by the shell.
   -name pattern
          Base of file name (the path with the leading directories removed)
          matches shell pattern pattern. 
   -delete
          Delete  files; true if removal succeeded.  If the removal failed,
          an error message is issued.  If -delete fails, find's exit status
          will be nonzero (when  it eventually exits).  Use of -delete 
          automatically turns on the -depth option.

Если вы не можете использовать findпо какой-либо причине, вот способ сделать это zsh(или другие оболочки). zshв сущности zsh, есть, вероятно, более простой способ сделать это, но так как я bashпарень, вот что я придумал:

for file in *; do if [[ ! "$file" == *.dmg ]]; then rm $file; fi; done
Тердон
источник
к сожалению, всякий раз, когда я использую find в моем mac, он просто выходит из текущего сеанса zsh без какого-либо уведомления. У тебя та же проблема ? find [Process completed]
Дзунг Нгуен
1
@nXqd см. обновленный ответ для способа сделать это без find. Я предлагаю вам опубликовать вопрос о вашей findпроблеме, однако, это не должно произойти. Если вы делаете, включите вывод type -a find.
Тердон
1
Даже в bash есть более простое решение: rm !(*.dmg)после shopt -s extglob.
Жиль "ТАК - перестань быть злым"
@terdon спасибо за ваши советы по отладке в оболочке. его вывод кажется правильным:find is a shell function find is /usr/bin/find
Дзунг Нгуен
@nXqd, что не правильно, это не должна быть функция оболочки, она должна быть только /usr/bin/find. У вас есть функция, findопределенная в одном из ваших файлов конфигурации bash. Поскольку вы используете OSX, это возможно ~/.profile.
Тердон
3

Другой способ удаления файлов является с find, xargsи rm:

find . -mindepth 1 -maxdepth 1 ! -name '*.dmg' -print0 | xargs -0 rm
Драгос Ризеску
источник