Exclui todos os arquivos, exceto arquivos com a extensão pdf em um diretório

47

Eu tenho um diretório que contém o seguinte:

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

Desejo excluir todos os arquivos, exceto x.pdf e a.pdf . Como faço isso no terminal? Não há subdiretórios, portanto, não há necessidade de recursão.

    
por Starkers 01.12.2014 / 12:47

11 respostas

62
cd <the directory you want>
find . -type f ! -iname "*.pdf" -delete
  • O primeiro comando levará você ao diretório no qual você deseja excluir seus arquivos
  • O segundo comando excluirá todos os arquivos, exceto aqueles que terminarem com .pdf no nome do arquivo

Por exemplo, se houver um diretório chamado temp em sua pasta pessoal:

cd ~/temp

depois, apague os arquivos:

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

Isso excluirá todos os arquivos, exceto xyz.pdf .

Você pode combinar esses dois comandos para:

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

. é o diretório atual. ! significa pegar todos os arquivos, exceto os com .pdf no final. -type f seleciona apenas arquivos, não diretórios. -delete significa excluí-lo.

NOTA: este comando irá apagar todos os arquivos (exceto arquivos pdf, mas incluindo arquivos ocultos) no diretório atual, bem como em todos os subdiretórios. ! deve vir antes de -name . simplesmente -name incluirá apenas .pdf , enquanto -iname incluirá .pdf e .PDF

Para excluir apenas no diretório atual e não nos subdiretórios, adicione -maxdepth 1 :

find . -maxdepth 1 -type f ! -iname "*.pdf" -delete
    
por edward torvalds 01.12.2014 / 12:51
41

Com a globalização expandida de bash , você pode remover quaisquer arquivos com extensões diferentes de .pdf usando

rm -- *.!(pdf)

Como observado por @pts, os caracteres -- indicam o final de qualquer opção de comando, tornando o comando seguro no caso raro de arquivos cujos nomes iniciam com um caractere - .

Se você quiser excluir arquivos sem qualquer extensão, assim como aqueles com extensões diferentes de .pdf , então, como apontado por @DennisWilliamson, você poderia usar

rm -- !(*.pdf)

A globalização estendida deve ser ativada por padrão, mas se não for possível, use

shopt -s extglob

Especialmente se você pretende usar isso dentro de um script, é importante observar que, se a expressão não corresponder a nada (ou seja, se não houver arquivos não-pdf no diretório), por padrão, a glob será passada não expandido para o comando rm , resultando em um erro como

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

Você pode modificar esse comportamento padrão usando a opção nullglob shell, mas isso tem seu próprio problema. Para uma discussão mais completa, veja NullGlob - Greg's Wiki

    
por steeldriver 01.12.2014 / 13:11
17

Excluir para o lixo :

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

Ou via o comando mv (mas desta forma você não pode restaurá-lo da Lixeira, pois ele não registra informações .trashinfo, então isso significa que você moveu seus arquivos para um destino onde está como seguindo).

mv !(*.pdf) ~/.local/share/Trash/files
    
por αғsнιη 01.12.2014 / 17:09
14

A abordagem mais fácil: Crie outro diretório em algum lugar (se você estiver apenas excluindo em um diretório, não recursivamente, pode até ser um subdiretório); mova todos os .pdf para lá; excluir tudo mais; mova as costas do pdf; exclua o diretório intermediário.

Rápido, fácil, você pode ver exatamente o que está fazendo. Apenas certifique-se de que o diretório intermediário esteja no mesmo dispositivo que o diretório que você está limpando, para que os movimentos sejam renomeados, não cópias!

    
por Jerry 01.12.2014 / 16:45
4

Use o GLOBIGNORE de bash:

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

Da página de man do bash:

GLOBIGNORE:

            A colon-separated list of patterns defining the set
            of filenames to be ignored by pathname expansion.

Um teste rápido:

mkdir /tmp/foooooo
cd /tmp/foooooo
touch x.pdf y.zip z.mp3 a.pdf
GLOBIGNORE=x.pdf:a.pdf
ls -1 *

Saída:

y.zip
z.mp3
    
por Cyrus 06.06.2015 / 18:51
3

Eu costumo resolver esses problemas a partir do interpretador interativo do Python:

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

Pode ser mais longo do que um one-liner com find ou xargs , mas é extremamente resiliente e eu sei exatamente o que ele faz, sem ter que pesquisá-lo primeiro.

    
por mic_e 02.12.2014 / 22:58
2

Tenha cuidado e componha: use xargs

Aqui está uma abordagem que eu gosto, porque me permite ter muito cuidado: componha uma maneira de mostrar apenas os arquivos que eu quero excluir e, em seguida, envie-os para rm using xargs . Por exemplo:

  • ls me mostra tudo
  • ls | grep pdf mostra os arquivos que eu quero manter. Hmm.
  • ls | grep -v pdf mostra o contrário: todos exceto o que eu quero manter. Em outras palavras, mostra a lista de itens que desejo excluir. Eu posso confirmar isso antes de fazer qualquer coisa perigosa.
  • ls | grep -v pdf | xargs rm envia exatamente essa lista para rm para exclusão

Como eu disse, eu principalmente gosto disso pela segurança que ele oferece: nenhum rm * acidental para mim. Duas outras vantagens:

  • É composable; você pode usar ls ou find para obter a lista inicial, como preferir. Você pode usar qualquer outra coisa que desejar no processo de restringir essa lista - outro grep , alguns awk ou o que for. Se você precisasse apagar apenas os arquivos cujos nomes continham uma cor, você poderia construí-lo da mesma maneira.
  • Você pode usar cada ferramenta para seu objetivo principal. Eu prefiro usar find para localizar e rm para remoção, em vez de ter que lembrar que find aceita uma -delete flag. E se você fizer isso, novamente, você pode compor soluções alternativas; talvez, em vez de rm , você possa criar um comando trash que mova o arquivo para a lixeira (permitindo "undeletion") e canalize para ele em vez de rm . Você não precisa ter find suporte para essa opção, basta enviar para ele.

Atualizar

Veja os comentários de @pabouk sobre como modificar isso para manipular alguns casos de borda, como quebras de linha em nomes de arquivos, nomes de arquivos como my_pdfs.zip , etc.

    
por Nathan Long 01.12.2014 / 22:39
2

melhor resposta (em comparação com a minha resposta anterior) para esta questão será usando o poderoso comando file .

$ file -i abc.pdf
abc: application/pdf; charset=binary

agora seu problema:

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

o trabalho do comando for é fornecer os arquivos no diretório atual na forma da variável $var . O comando if-then exibe os nomes dos arquivos pdf tomando o status de saída do comando 0 from file -i "$var" | grep -q 'application/pdf\;' , e dará status de saída de 0 somente se encontrar arquivos em pdf.

    
por edward torvalds 04.06.2015 / 18:39
1
rm $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print }')

Atenção! Melhor tente primeiro

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

Leia como, remova todos os arquivos que não são a.pdf ou x.pdf .

Isso funciona com o uso de 2 globs estendidos, o% externo !() para negar o glob contido que requer que o glob corresponda a um ou mais dos padrões a ou x antes do sufixo .pdf . Veja 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
    
por shalomb 17.05.2015 / 12:48
1

caminho de shell portátil

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

Praticamente POSIX e compatível com qualquer shell estilo Bourne ( ksh , bash , dash ). Adequado para scripts portáteis e quando você não pode usar o globbing expandido de bash .

perl:

$ perl -le 'opendir(my $d,"."); foreach my $f (grep(-f && !/.pdf/ , readdir($d))){unlink $f};closedir $d'                                                             

Ou ligeiramente mais limpo:

$ perl -le 'opendir(my $d,"."); map{ unlink $_ } grep(-f "./$_" && !/.pdf/ , readdir($d));closedir $d'

python alternativa

python -c 'import os;map(lambda x: os.remove(x), filter(lambda x: not x.endswith(".pdf"),os.listdir(".")))'
    
por Sergiy Kolodyazhnyy 08.11.2017 / 10:16