Удалить все файлы, кроме файлов с расширением pdf в каталоге

48

У меня есть каталог, который содержит следующее:

x.pdf
y.zip
z.mp3
a.pdf

Я хочу удалить все файлы, кроме x.pdf и a.pdf . Как это сделать с терминала? Нет никаких подкаталогов, поэтому нет необходимости в какой-либо рекурсии.

    
задан Starkers 01.12.2014 в 12:47
источник

11 ответов

63
cd <the directory you want>
find . -type f ! -iname "*.pdf" -delete
  • Первая команда приведет вас в каталог, в котором вы хотите удалить свои файлы.
  • Вторая команда удалит все файлы, кроме тех, которые заканчиваются на .pdf в имени файла

Например, если в вашей домашней папке есть каталог с именем temp :

cd ~/temp

затем удалите файлы:

find . -type f ! -iname "*.pdf" -delete

Это приведет к удалению всех файлов, кроме xyz.pdf .

Вы можете объединить эти две команды с:

find ~/temp -type f ! -iname "*.pdf" -delete

. - текущий каталог. ! означает взять все файлы, кроме тех, у кого .pdf в конце. -type f выбирает только файлы, а не каталоги. -delete означает его удаление.

ПРИМЕЧАНИЕ. Эта команда удалит все файлы (кроме файлов PDF, включая скрытые файлы) в текущем каталоге, а также во всех подкаталогах. ! должно превышать -name . просто -name будет включать только .pdf , а -iname будет включать в себя как .pdf , так и .PDF

Чтобы удалить только в текущем каталоге, а не в подкаталогах, добавьте -maxdepth 1 :

find . -maxdepth 1 -type f ! -iname "*.pdf" -delete
    
ответ дан Edward Torvalds 01.12.2014 в 12:51
источник
41

С расширенным расширением shell co_de% вы можете удалить любые файлы с расширениями, отличными от bash , используя

rm -- *.!(pdf)

Как отмечено @pts, символы .pdf указывают на конец любых параметров команды, делают команду безопасной в редком случае файлов, имена которых начинаются с символа -- .

Если вы хотите удалить файлы без каких-либо расширений, а также с расширениями, отличными от - , то, как указал @DennisWilliamson, вы можете использовать

rm -- !(*.pdf)

Расширенное глобальное включение должно быть включено по умолчанию, но если вы не можете сделать это, используя

shopt -s extglob

Особенно, если вы намерены использовать это внутри скрипта, важно отметить, что если выражение не соответствует чему-либо (т. е. если в каталоге нет файлов без PDF-файла), то по умолчанию glob будет передан не обновляется до команды .pdf , что приводит к ошибке, например

rm: cannot remove '*.!(pdf)': No such file or directory

Вы можете изменить это поведение по умолчанию, используя опцию rm shell, однако это имеет свою проблему. Для более подробного обсуждения см. NullGlob - Вики-страница Грега

    
ответ дан steeldriver 01.12.2014 в 13:11
17

Удалить в корзину :

$ cd <the directory you want>
$ gvfs-trash !(*.pdf)

Или через команду mv (но таким образом вы не можете восстановить ее из корзины, так как она не записывает информацию .trashinfo, поэтому это означает, что вы переместили ваши файлы в destination , где это как указано ниже).

mv !(*.pdf) ~/.local/share/Trash/files
    
ответ дан sddgob 01.12.2014 в 17:09
14

Самый простой способ: создать другой каталог где-нибудь (если вы удаляете только один каталог, а не рекурсивно, он может даже быть подкаталогом); переместите все .pdf; удалять все остальное; переместите обратно pdf; удалите промежуточный каталог.

Быстро, легко, вы можете точно видеть, что вы делаете. Просто убедитесь, что промежуточный каталог находится на том же устройстве, что и очищаемый каталог, поэтому хосты переименовываются, а не копии!

    
ответ дан Jerry 01.12.2014 в 16:45
4

Использовать 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
    
ответ дан Cyrus 06.06.2015 в 18:51
3

Я обычно решаю такие проблемы у интерактивного интерпретатора Python:

[email protected] ~ $ python
>>> import os
>>> for f in os.listdir('.'):
...   if not f.endswith('.pdf'):
...     os.remove(f)

Он может быть длиннее, чем однострочный с find или xargs , но он чрезвычайно устойчив, и я точно знаю, что он делает, не изучая его в первую очередь.

    
ответ дан mic_e 02.12.2014 в 22:58
3

Будьте осторожны и составите: используйте xargs

Вот такой подход, который мне нравится, потому что он позволяет мне быть очень осторожным: составить способ показать только файлы, которые я хочу удалить, а затем отправить их на rm , используя xargs . Например:

  • ls показывает мне все
  • ls | grep pdf показывает мне файлы, которые я хочу сохранить. Хм.
  • ls | grep -v pdf показывает противоположное: все кроме , что я хочу сохранить. Другими словами, он показывает список вещей, которые я хочу удалить. Я могу подтвердить это, прежде чем делать что-нибудь опасное.
  • ls | grep -v pdf | xargs rm отправляет именно этот список в rm для удаления

Как я уже сказал, мне в основном нравится это для обеспечения безопасности: для меня нет случайного rm * . Два других преимущества:

  • Это композиционно; вы можете использовать ls или find , чтобы получить исходный список, как вы предпочитаете. Вы можете использовать все, что вам нравится, в процессе сужения этого списка - еще один grep , некоторые awk или что-то еще. Если вам нужно удалить только файлы, чьи имена содержат цвет, вы можете создать его таким же образом.
  • Вы можете использовать каждый инструмент для своей основной цели. Я предпочитаю использовать find для поиска и rm для удаления, в отличие от необходимости помнить, что find принимает флаг -delete . И если вы это сделаете, опять же, вы можете составить альтернативные решения; вместо rm , вы можете создать команду trash , которая перемещает файл в корзину (разрешая «undeletion») и ссылается на это вместо rm . Вам не нужно иметь find поддержки этой опции, вы просто подключаетесь к ней.

Update

См. комментарии от @pabouk о том, как изменить это, чтобы обрабатывать некоторые случаи ребер, такие как разрывы строк в именах файлов, имена файлов, такие как my_pdfs.zip и т. д.

    
ответ дан Nathan Long 01.12.2014 в 22:39
2

лучший ответ (по сравнению с моим предыдущим ответом) на этот вопрос будет с помощью мощной команды 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.

    
ответ дан Edward Torvalds 04.06.2015 в 18:39
1
rm $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')

Внимание! Лучше попробуйте сначала

ls -l $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')
    
ответ дан Martín-Blas Pérez Pinilla 03.12.2014 в 16:08
1
rm -i -- !(*@(a|x).pdf)

Прочитайте как, удалите все файлы, которые не являются a.pdf или x.pdf .

Это работает, используя 2 расширенных шара, внешний !() , чтобы отменить содержавшийся 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
    
ответ дан shalomb 17.05.2015 в 12:48
1

переносная оболочка

$ ksh -c 'for i in ./*; do case $i in *.pdf)continue;; *)rm "$i";; esac;done'

Довольно много POSIX и совместимо с любой оболочкой стиля Bourne ( ksh , bash , dash ). Хорошо подходит для переносных скриптов, и когда вы не можете использовать расширенную оболочку bash .

Perl:

$ 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(".")))'
    
ответ дан Sergiy Kolodyazhnyy 08.11.2017 в 10:16