Видаліть усі файли, крім файлів із розширенням pdf у каталозі


50

У мене є каталог, який містить наступне:

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

Я хочу видалити всі файли крім x.pdfі a.pdf. Як це зробити з терміналу? Немає підкаталогів, тому немає необхідності в будь-якій рекурсії.

Відповіді:


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

Дякую за відповідь. Чи можете ви допомогти мені трохи зрозуміти синтаксис? .означає "і"? !означає "крім" -nameозначає, що ви хочете виключити параметр імені, а потім -deleteдія, яку слід вжити при пошуку? Отже, він шукає все, крім "* .pdf" та видаляє їх? Або я неправильно зрозумів?
jessenorton

.означає поточний каталог. !означає взяти всі файли, окрім файлів, що мають .pdfкінець. -deleteозначає видалити його. я зрозумів зараз?
Едвард Торвальдс

@terdon Starkers сказав, що немає жодних підкаталогів. чекаю поганого редагування моєї відповіді, щоб бути більш широким
Едвард Торвальдс

+1 Вам слід було б включити -maxdepth 1параметр для початку. Потім запропонуйте видалити параметр у випадку, якщо потрібно видалити рекурсивно.
Tulains Córdova

3
це звернуло увагу на те, що нам слід використовувати -inameзамість цього -name, або файли з .PDFрозширенням проскакують.
муру

43

Завдяки bashрозширенню глобальної оболонки ви можете видалити будь-які файли з розширеннями, крім .pdfвикористання

rm -- *.!(pdf)

Як зазначає @pts, --символи вказують на завершення будь-яких параметрів команди, роблять команду безпечною у рідкісних випадках файлів, імена яких починаються з -символу.

Якщо ви хочете видалити файли без будь-якого розширення, а також ті, що мають не інші розширення .pdf, то, як вказував @DennisWilliamson, ви можете використовувати

rm -- !(*.pdf)

Розширений глобул повинен бути включений за замовчуванням, але якщо ні, то ви можете зробити це за допомогою

shopt -s extglob

Особливо, якщо ви маєте намір використовувати це всередині сценарію, важливо зауважити, що якщо вираз нічого не відповідає (тобто, якщо в каталозі немає файлів, що не належать до формату pdf), то за замовчуванням глобус буде передано нерозгорнуто до rmкоманда, в результаті чого виникає помилка

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

Ви можете змінити цю поведінку за замовчуванням за допомогою параметра nullglobоболонки, однак у неї є своя проблема. Для більш ретельного обговорення див. NullGlob - Вікі Грега


Краще підходити до ІМО.
Таккат

Що з файлами без розширення? FWIW, в zsh цеrm *~*.pdf
Emil Jeřábek

1
Я поставив би крапку в дужках.
Денніс Вільямсон

4
Ах, зірочка повинна також йти всередину: !(*.py). Також, імовірно, якщо ОП хоче лише залишитися лише файлами ".pdf", то файли без розширень також слід видалити і не ігнорувати.
Денніс Вільямсон

1
Цей підхід простіший і охайніший, ніж прийнята відповідь.
Петро

18

Видалити в кошик :

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

Або за допомогою mvкоманди (але таким чином ви не можете відновити його з кошика, оскільки він не записує .trashinfo інформацію, тож це означає, що ви перемістили файли до місця призначення, де воно є наступним).

mv !(*.pdf) ~/.local/share/Trash/files

6
Цей підхід набагато безпечніший, ніж безпосередньо використання rm.
Сет

14

Найпростіший підхід: створити інший каталог десь (якщо ви видаляєте лише в одному каталозі, а не рекурсивно, це навіть може бути підкаталог); перемістити всі файли .pdf туди; видалити все інше; перемістити назад PDF-файл; видалити проміжний каталог.

Швидко, просто, ви можете точно бачити, що ви робите. Просто переконайтеся, що проміжний каталог знаходиться на тому ж пристрої, що і каталог, який ви очищаєте, щоб переміщення були перейменованими, а не копіями!


4
+1 Знову за коментарем, який має сенс для початківця користувача, що майже точно не призведе до випадкового видалення файлів.
трогнандри

4

Використовуйте GLOBIGNORE bash:

GLOBIGNORE=x.pdf:a.pdf
rm *
unset GLOBIGNORE

З сторінки чоловіка bash:

GLOBIGNORE:

            Список візерунків, розділених двокрапкою, визначає набір
            імен файлів, які слід ігнорувати шляхом розширення імені шляху.

Швидкий тест:

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

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команду, яка переміщує файл у кошик (що дозволяє "вимкнути") і передавати на нього замість rm. Вам не потрібно мати findпідтримку цієї опції, ви просто пропонуєте її.

Оновлення

Перегляньте коментарі @pabouk про те, як змінити це для оброблення деяких кращих випадків, таких як розриви рядків у назвах файлів, назви імен файлів my_pdfs.zipтощо.


4
Тут я помітив три проблеми: а) Він буде виключати будь-який файл, що містить pdfдесь його ім’я. --- б) Він видалить файли PDF, якщо будь-який лист у суфіксі є великим регістром. --- в) Недоцільно використовувати вихід ls. Він не працюватиме з іменами файлів, що містять нові рядки. Деякі реалізації lsзамінюють спеціальні символи, наприклад, вкладку ?. --- Краще використовувати: find -maxdepth 1 -print0. (не настільки короткий, як ls:) ----- Для вирішення а) та б) використовуйте grep -vi '\.pdf$'--- повне (але тільки GNU) рішення:find -maxdepth 1 -print0 | grep -viz '\.pdf$' | xargs -0 rm
pabouk

1
Я розумію, що ви мали на увазі рішення як "інтерактивний" процес з декількома ручними ітераціями, але перевірки навряд чи можуть бути використані для довгих списків файлів, і проблеми, згадані вище, можуть легко усунути помилки.
пабук

1
@pabouk хороші бали; реальний світ завжди ускладнює речі, і ваші виправлення корисні. :) Але я все ж думаю, що цей загальний підхід найкращий. Якщо файлів занадто багато, щоб візуально все підтвердити, ви можете | head -20принаймні побачити, чи це виглядає приблизно правильно, тоді як, якщо ви просто rm my_pattern, у вас немає шансів помітити велику помилку.
Натан Лонг

1
Ви можете знайти, щоб показати вам файли, перш ніж ви їх також видалите, залиште -delete і просто використовуйте find . -type f ! -name "*.pdf"для друку на консоль, або передайте менше або файл. [а потім перейдіть до xargs до rm за бажанням, як коментарі pabouk (з -print0 | ... -0 для дивних файлів)]
Xen2050,

3

Зазвичай я вирішую такі проблеми від інтерактивного інтерпретатора Python:

mic@mic ~ $ python
>>> import os
>>> for f in os.listdir('.'):
...   if not f.endswith('.pdf'):
...     os.remove(f)

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


Для тих, хто все більше нервує з кожним додатковим рядком, ми можемо перетворити його в один:for item in [f for f in os.listdir('.') if not f.endswith('.pdf')]: os.remove(item)
Яків Влійм

python -c "import os; for f in os.listdir('.'): if not f.endswith('.pdf'): os.remove(f)"
mic_e

[os.remove(f) for f in os.listdir('.') if not f.endswith('.pdf')]
mic_e

приємно! другий дає мені синтаксичну помилку, не розумію, чому.
Яків Влійм

дивно; він працює як з python 3.4, так і python 2.7 у моїй системі.
mic_e

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.


1
rm $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')

Увага! Краще спробуйте спочатку

ls -l $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')

2
Цього, це помилка в багатьох способах: smallo.ruhr.de/award.html#ls , smallo.ruhr.de/award.html#grep , і він повністю ігнорує імена файлів з пробілом або спеціальними символами.
Девід Фоерстер

1
Ви дійсно повинні використовувати -iз grepдля обліку регістра відповідності.
муру

1
rm -i -- !(*@(a|x).pdf)

Читати як, видалити всі файли, які не є a.pdfабо x.pdf.

Це працює, використовуючи 2 розширені глобуси, зовнішні !()для того, щоб заперечувати міститься глобус, який сам вимагає, щоб глобус повинен відповідати одному або більше aабо xшаблонам перед .pdfсуфіксом. Дивіться глобус # 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

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(".")))'

0

Будьте уважні до того, що ви видаляєте!

Безпечний спосіб перевірити його перед спробою видалити - це спробувати спочатку ls, оскільки деякі неприховані поведінки можуть видалити небажані файли. І це можна зробити безпосередньо за межами каталогу. lsподібний rm, так:

ls sub/path/to/files/!(*.pdf)

Це буде список

y.zip
z.mp3

Тепер ви можете побачити, що ви видаляєте, і можете їх безпечно видалити:

rm sub/path/to/files/!(*.pdf)

І це все. Йо може використовувати підстановку, *щоб бути більш вибірковою, як зберігання лише програмних документів курсу:

rm sub/path/to/files/!(*programming*)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.