У меня есть каталог, который содержит следующее:
x.pdf
y.zip
z.mp3
a.pdf
Я хочу удалить все файлы, кроме x.pdf
и a.pdf
. Как мне это сделать из терминала? Здесь нет подкаталогов, поэтому нет необходимости в какой-либо рекурсии.
У меня есть каталог, который содержит следующее:
x.pdf
y.zip
z.mp3
a.pdf
Я хочу удалить все файлы, кроме x.pdf
и a.pdf
. Как мне это сделать из терминала? Здесь нет подкаталогов, поэтому нет необходимости в какой-либо рекурсии.
Ответы:
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
значит удалить это.
!
должен прийти раньше -name
. просто -name
включит только .pdf
, пока -iname
включит .pdf
и.PDF
Чтобы удалить только в текущем каталоге, а не в подкаталогах, добавьте -maxdepth 1
:
find . -maxdepth 1 -type f ! -iname "*.pdf" -delete
.
означает текущий каталог. !
означает взять все файлы, кроме того, что .pdf
в конце. -delete
значит удалить это. я теперь ясно?
-maxdepth 1
параметр для начала. Затем предложите удалить параметр в случае, если вы хотите удалить рекурсивно.
С bash
«s расширенной подстановкой оболочки, вы можете удалить любые файлы с другими расширениями , чем с .pdf
помощью
rm -- *.!(pdf)
Как отмечает @pts, --
символы указывают на конец любых параметров команды, что делает команду безопасной в редких случаях файлов, имена которых начинаются с -
символа.
Если вы хотите удалить файлы без каких-либо расширений, а также файлы с расширениями, отличными от .pdf
, то, как указано @DennisWilliamson, вы можете использовать
rm -- !(*.pdf)
Расширенное глобирование должно быть включено по умолчанию, но если нет, вы можете сделать это, используя
shopt -s extglob
Особенно, если вы намереваетесь использовать это внутри скрипта, важно отметить, что если выражение не совпадает с чем-либо (то есть, если в каталоге нет файлов, не относящихся к pdf), то по умолчанию глобус будет передаваться без расширения. rm
команда, приводящая к ошибке вроде
rm: cannot remove `*.!(pdf)': No such file or directory
Вы можете изменить это поведение по умолчанию, используя nullglob
опцию оболочки, однако это имеет свою проблему. Для более подробного обсуждения смотрите NullGlob - Wiki Грега
rm *~*.pdf
!(*.py)
. Также, предположительно, если OP хочет, чтобы оставались только файлы «.pdf», то файлы без расширений также должны быть удалены и не игнорироваться.
$ cd <the directory you want>
$ gvfs-trash !(*.pdf)
Или с помощью mv
команды (но таким образом вы не можете восстановить его из корзины, так как он не записывает информацию .trashinfo, так что это означает, что вы переместили ваши файлы в место назначения , как указано ниже).
mv !(*.pdf) ~/.local/share/Trash/files
rm
.
Самый простой подход: создать другой каталог где-нибудь (если вы удаляете только один каталог, а не рекурсивно, это может быть даже подкаталог); переместить все .pdf туда; удалить все остальное; переместить PDF обратно; удалить промежуточный каталог.
Быстро, просто, вы точно видите, что делаете. Просто убедитесь, что промежуточный каталог находится на том же устройстве, что и каталог, который вы очищаете, чтобы перемещения были переименованиями, а не копиями!
Используйте 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
Вот подход, который мне нравится, потому что он позволяет мне быть очень осторожным: придумать способ показать только те файлы, которые я хочу удалить, а затем отправить их в 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
, и т. Д.
pdf
где-либо его имя. --- b) Он удалит файлы PDF, если любая из букв в суффиксе будет прописной. --- в) Не рекомендуется использовать вывод ls
. Он не будет работать с именами файлов, содержащими переводы строк. Некоторые реализации ls
заменяют специальные символы, например tab ?
. --- Лучше использования: find -maxdepth 1 -print0
. (не так коротко, как ls
:) ----- Для разрешения а) и б) используйте grep -vi '\.pdf$'
--- полное (но только для GNU) решение:find -maxdepth 1 -print0 | grep -viz '\.pdf$' | xargs -0 rm
| head -20
хотя бы посмотреть, выглядит ли это примерно правильно, а если вы просто rm my_pattern
, у вас нет шансов обнаружить большую ошибку.
find . -type f ! -name "*.pdf"
для печати на консоль, или для передачи на less или в файл. [и затем направьте xargs к rm, если хотите, как комментарии Пабука (с -print0 | ... -0 для странных имен файлов)]
Обычно я решаю такие проблемы с помощью интерактивного интерпретатора 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)"
[os.remove(f) for f in os.listdir('.') if not f.endswith('.pdf')]
Лучшим ответом (по сравнению с моим предыдущим ответом) на этот вопрос будет использование мощной 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
from 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}')
-i
с grep
для сопоставления без учета регистра.
rm -i -- !(*@(a|x).pdf)
Читать как, удалить все файлы, которые не являются a.pdf
или x.pdf
.
Это работает, используя 2 расширенных глоба, внешний !()
для отмены содержащегося глобуса, который сам по себе требует, чтобы шар соответствовал одному или нескольким из 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(".")))'
Будьте осторожны с тем, что вы удаляете!
Безопасный способ проверить его перед попыткой удаления - это сначала выполнить тестирование 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*)
.
значит "а"?!
означает «кроме»-name
означает, что вы хотите исключить с помощью параметра имени, а затем какое-delete
действие предпринять при поиске? Так он ищет все, кроме "* .pdf" и удаляет их? Или я неправильно понял?