У меня есть каталог, который содержит следующее:
x.pdf
y.zip
z.mp3
a.pdf
Я хочу удалить все файлы, кроме x.pdf и a.pdf. Как это сделать с терминала? Нет никаких подкаталогов, поэтому нет необходимости в какой-либо рекурсии.
С расширенным чередованием оболочки bash вы можете удалить любые файлы с расширениями, отличными от .pdf, используя
rm -- *.!(pdf)
Как отмечено @pts, символы -- указывают на конец любых параметров команды, сделайте команду безопасной в редких случаях с файлами, имена которых начинаются с символа -.
Если вы хотите удалять файлы без каких-либо расширений, а также с расширениями, отличными от [ f9], то, как указал @DennisWilliamson, вы можете использовать
rm -- !(*.pdf)
. Расширенное глобальное включение должно быть включено по умолчанию, но если вы не можете сделать это, используя
shopt -s extglob
[ ! d4] Особенно, если вы намерены использовать это внутри скрипта, важно отметить, что если выражение не соответствует чему-либо (т. е. если в каталоге нет файлов без PDF-файлов), то по умолчанию glob будет передан без изменений в команду rm, что приведет к ошибке, например
rm: cannot remove `*.!(pdf)': No such file or directory
. Вы можете изменить это поведение по умолчанию, используя опцию оболочки nullglob, однако это имеет свою проблему. Для более подробного обсуждения см. NullGlob - Wiki
Грега]Удалить в корзину:
$ cd <the directory you want>
$ gvfs-trash !(*.pdf)
Или с помощью команды mv (но таким образом вы не можете восстановить ее из корзины, поскольку она не записывает информацию .trashinfo, поэтому это означает, что вы переместили свой файлы в пункт назначения, где он следующий).
mv !(*.pdf) ~/.local/share/Trash/files
Самый простой подход: создайте другой каталог где-нибудь (если вы удаляете только один каталог, а не рекурсивно, он может даже быть подкаталогом); переместите все .pdf; удалять все остальное; переместите обратно pdf; удалите промежуточный каталог.
Быстро, легко, вы можете точно видеть, что вы делаете. Просто убедитесь, что промежуточный каталог находится на том же устройстве, что и очищаемый каталог, так что хосты переименовываются, а не копии!
Используйте GLOBIGNORE из bash:
GLOBIGNORE=x.pdf:a.pdf
rm *
unset GLOBIGNORE
Из справочной страницы bash:
GLOBIGNORE: A colon-separated list of patterns defining the set of filenames to be ignored by pathname expansion.Быстрая проверка:
mkdir /tmp/foooooo
cd /tmp/foooooo
touch x.pdf y.zip z.mp3 a.pdf
GLOBIGNORE=x.pdf:a.pdf
ls -1 *
Выход:
y.zip z.mp3Я обычно решаю такие проблемы из интерактивного интерпретатора Python:
mic@mic ~ $ python
>>> import os
>>> for f in os.listdir('.'):
... if not f.endswith('.pdf'):
... os.remove(f)
Он может быть длиннее однострочного с find или xargs, но он чрезвычайно устойчив, и я знаю точно, что он делает, не имея необходимости сначала исследовать его.
Вот такой подход, который мне нравится, потому что он позволяет мне быть очень осторожным: составить способ показать только файлы, которые я хочу удалить, а затем отправить их в rm используя xargs. Например:
ls показывает мне все ls | grep pdf показывает мне файлы, которые я хочу сохранить. Хм. ls | grep -v pdf показывает противоположное: все, кроме того, что я хочу сохранить. Другими словами, он показывает список вещей, которые я хочу удалить. Я могу подтвердить это, прежде чем делать что-нибудь опасное. ls | grep -v pdf | xargs rm отправляет именно этот список в rm для удаленияКак я уже сказал, мне в основном нравится это для обеспечения безопасности: для меня нет случайных rm *. Два других преимущества:
ls показывает мне все Вы можете использовать каждый инструмент для своей основной цели. Я предпочитаю использовать find для поиска и rm для удаления, в отличие от необходимости помнить, что find принимает флаг -delete. И если вы это сделаете, опять же, вы можете составить альтернативные решения; возможно, вместо rm вы могли бы создать команду trash, которая перемещает файл в корзину (разрешая «undeletion») и pipe на это вместо rm. Вам не нужно иметь find поддержку этого параметра, вы просто подключаетесь к нему.См. комментарии от @pabouk о том, как изменить это, чтобы обрабатывать некоторые случаи краев, такие как разрывы строк в именах файлов, имена файлов, такие как my_pdfs.zip и т. д.
лучше ответить (по сравнению с моим предыдущим ответом) на этот вопрос будет с помощью мощной команды file.
$ file -i abc.pdf
abc: application/pdf; charset=binary
теперь ваша проблема:
cd <the directory you want to search in>
for var in ./*
do
if file -i "$var" | grep -q 'application/pdf\;'
then
echo "$var"
fi
done
задание команды for дает файлы в текущем каталоге в виде переменной $var. Команда if-then выводит имена файлов в формате pdf, принимая статус выхода из 0 из команды file -i "$var" | grep -q 'application/pdf\;', она выдаст статус выхода 0 только в том случае, если находит файлы PDF.
rm $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')
Внимание! Лучше попробуйте сначала
ls -l $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')
rm -i -- !(*@(a|x).pdf)
Прочитайте как, удалите все файлы, которые не являются a.pdf или x.pdf.
Это работает, используя два расширенных шара, внешний !(), чтобы скрыть содержащиеся в нем glob который сам требует, чтобы glob должен соответствовать одному или нескольким шаблонам a или x до суффикса .pdf. См. Glob # extglob.
$ ls -a
.dotfile1 .dotfile2 a.pdf x.pdf y.zip z.mp3
$ echo -- !(a.pdf)
-- x.pdf y.zip z.mp3
$ echo -- !(x.pdf)
-- a.pdf y.zip z.mp3
$ echo -- !(a.pdf|x.pdf)
-- y.zip z.mp3
$ echo -- !(@(a|x).pdf) # NOTE.that this matches the .dotfiles* as well
-- . .. .dotfile1 .dotfile2 y.zip z.mp3
$ echo -- !(*@(a|x).pdf) # but this doesn't
-- y.zip z.mp3
$ echo rm -i -- !(*@(a|x).pdf)
rm -i -- y.zip z.mp3
$ ksh -c 'for i in ./*; do case $i in *.pdf)continue;; *)rm "$i";; esac;done'
Довольно много POSIX и совместимо с любой оболочкой типа Bourne (ksh, bash, dash). Хорошо подходит для переносных скриптов и когда вы не можете использовать расширенную оболочку bash.
$ perl -le 'opendir(my $d,"."); foreach my $f (grep(-f && !/.pdf/ , readdir($d))){unlink $f};closedir $d'
Или немного чище:
$ perl -le 'opendir(my $d,"."); map{ unlink $_ } grep(-f "./$_" && !/.pdf/ , readdir($d));closedir $d'
python -c 'import os;map(lambda x: os.remove(x), filter(lambda x: not x.endswith(".pdf"),os.listdir(".")))'