Elimina tutti i file tranne i file con estensione pdf in una directory


50

Ho una directory che contiene quanto segue:

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

Voglio eliminare tutti i file tranne x.pdfe a.pdf. Come posso farlo dal terminale? Non ci sono sottodirectory quindi non c'è bisogno di alcuna ricorsione.

Risposte:


63
cd <the directory you want>
find . -type f ! -iname "*.pdf" -delete
  • Il primo comando ti porterà nella directory in cui vuoi eliminare i tuoi file
  • Il secondo comando eliminerà tutti i file tranne quelli che terminano con un .pdfnome file

Ad esempio, se esiste una directory chiamata tempnella cartella principale:

cd ~/temp

quindi eliminare i file:

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

Ciò eliminerà tutti i file tranne xyz.pdf.

È possibile combinare questi due comandi per:

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

.è la directory corrente. !significa prendere tutti i file tranne quelli con .pdfalla fine. -type fseleziona solo i file, non le directory. -deletesignifica eliminarlo.

NOTA: questo comando eliminerà tutti i file (tranne i file pdf ma inclusi i file nascosti) nella directory corrente e in tutte le sottodirectory. !deve venire prima -name. -nameincluderà semplicemente solo .pdf, mentre -inameincluderà sia .pdfe.PDF

Per eliminare solo nella directory corrente e non nelle sottodirectory aggiungere -maxdepth 1:

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

Grazie per la risposta. Potete aiutarmi a capire un po 'la sintassi? .significa "e"? !significa "tranne" -namesignifica che si desidera escludere con un parametro name e quindi -deletel'azione da intraprendere al momento della ricerca? Quindi cerca tutto tranne "* .pdf" e li elimina? O ho frainteso?
jessenorton,

.indica la directory corrente. !significa prendere tutti i file tranne quello con .pdfalla fine. -deletesignifica eliminarlo. sono chiaro ora?
Edward Torvalds,

@terdon Starkers ha detto che non ci sono sottodirectory. In attesa di modifica la mia risposta sarà più ampia
Edward Torvalds,

+1 Dovresti aver incluso il -maxdepth 1parametro per cominciare. Quindi suggerire di rimuovere il parametro nel caso si desideri eliminare in modo ricorsivo.
Tulains Córdova,

3
questo ha portato alla mia attenzione che dovremmo usare al -inameposto di -name, oppure i file con .PDFestensione scivoleranno attraverso.
muru,

43

Con bashil globbing esteso della shell, è possibile rimuovere qualsiasi file con estensioni diverse .pdfdall'uso

rm -- *.!(pdf)

Come notato da @pts, i --caratteri indicano la fine di qualsiasi opzione di comando, rendono il comando sicuro nel raro caso di file il cui nome inizia con un -carattere.

Se si desidera eliminare i file senza alcuna estensione e quelli con estensioni diverse da .pdf, quindi come sottolineato da @DennisWilliamson è possibile utilizzare

rm -- !(*.pdf)

Il globbing esteso dovrebbe essere abilitato per impostazione predefinita, ma in caso contrario è possibile farlo utilizzando

shopt -s extglob

Soprattutto se si intende utilizzarlo all'interno di uno script, è importante notare che se l'espressione non corrisponde a nulla (ovvero se non ci sono file non pdf nella directory), per impostazione predefinita il glob verrà passato non espanso al rmcomando, con conseguente errore come

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

È possibile modificare questo comportamento predefinito utilizzando l' nullglobopzione shell, tuttavia ha un suo problema. Per una discussione più approfondita vedi NullGlob - Greg's Wiki


Approccio migliore all'IMO.
Takkat,

Che dire dei file senza estensione? FWIW, in zsh èrm *~*.pdf
Emil Jeřábek il

1
Metterei il punto tra parentesi.
Dennis Williamson,

4
Ah, l'asterisco dovrebbe anche andare dentro: !(*.py). Inoltre, presumibilmente, se l'OP desidera che rimangano solo i file ".pdf", anche i file senza estensioni devono essere eliminati e non ignorati.
Dennis Williamson,

1
Questo approccio è più semplice e ordinato rispetto alla risposta accettata.
Peter,

18

Elimina nel cestino :

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

O tramite mvcomando (ma in questo modo non è possibile ripristinarlo dal Cestino poiché non registra le informazioni .trashinfo, quindi questo significa che hai spostato i tuoi file in una destinazione dove è come segue).

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

6
Questo approccio è molto più sicuro rispetto all'utilizzo diretto rm.
Seth,

14

L'approccio più semplice: creare un'altra directory da qualche parte (se si sta eliminando solo una directory, non ricorsivamente, può anche essere una sottodirectory); sposta lì tutti i .pdf; elimina tutto il resto; sposta indietro il pdf; elimina la directory intermedia.

Veloce, facile, puoi vedere esattamente cosa stai facendo. Assicurati solo che la directory intermedia sia sullo stesso dispositivo della directory che stai ripulendo in modo che le mosse siano rinominazioni, non copie!


4
+1 Ancora per un commento che ha senso per l'utente inesperto, che quasi sicuramente non porterà all'eliminazione involontaria dei file.
Trognandro

4

Usa GLOBIGNORE di bash:

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

Dalla pagina man di bash:

GLOBIGNORE:

            Un elenco separato da due punti di motivi che definiscono il set
            di nomi di file che devono essere ignorati dall'espansione del percorso.

Un rapido test:

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

Produzione:

y.zip
z.mp3

3

Fai attenzione e componi: usa xargs

Ecco un approccio che mi piace, perché mi consente di stare molto attento: componi un modo per mostrare solo i file che voglio eliminare, quindi inviali a rmutilizzare xargs. Per esempio:

  • ls mi mostra tutto
  • ls | grep pdfmi mostra i file che voglio conservare. Hmm.
  • ls | grep -v pdfmostra il contrario: tutti tranne quello che voglio mantenere. In altre parole, mostra l'elenco delle cose che voglio eliminare. Posso confermarlo prima di fare qualcosa di pericoloso.
  • ls | grep -v pdf | xargs rminvia esattamente tale elenco rmper la cancellazione

Come ho detto, mi piace principalmente questo per la sicurezza che fornisce: nessun incidente rm *per me. Altri due vantaggi:

  • È compostabile; puoi usare lso findper ottenere l'elenco iniziale, come preferisci. Puoi usare qualsiasi altra cosa ti piaccia nel processo di restringimento di tale elenco - un altro grep, alcuni awko qualunque cosa. Se fosse necessario eliminare solo i file i cui nomi contengono un colore, è possibile crearlo nello stesso modo.
  • Puoi utilizzare ogni strumento per il suo scopo principale. Preferisco usare findper trovare e rmrimuovere, piuttosto che dover ricordare che findaccetta una -deletebandiera. E se lo fai, ancora una volta, puoi comporre soluzioni alternative; forse invece di rm, potresti creare un trashcomando che sposta il file nel cestino (consentendo "undeletion") e reindirizza a quello invece di rm. Non è necessario disporre del findsupporto per questa opzione, è sufficiente eseguire il pipe.

Aggiornare

Vedi i commenti di @pabouk su come modificarlo per gestire alcuni casi limite, come interruzioni di riga nei nomi di file, nomi di file come my_pdfs.zip, ecc.


4
Ho notato tre problemi qui: a) Escluderà qualsiasi file contenente pdfovunque nel suo nome. --- b) Eliminerà i file PDF se una delle lettere nel suffisso è in maiuscolo. --- c) Non è una buona idea usare l'output di ls. Non funzionerà con nomi di file contenenti newline. Alcune implementazioni di lssostituzione di caratteri speciali, ad esempio tab by ?. --- E 'meglio usare: find -maxdepth 1 -print0. (non così breve come ls:) ----- Per risolvere a) eb) utilizzare grep -vi '\.pdf$'--- soluzione completa (ma solo GNU):find -maxdepth 1 -print0 | grep -viz '\.pdf$' | xargs -0 rm
pabouk

1
Comprendo che intendevi la soluzione come un processo "interattivo" con più iterazioni manuali, ma i controlli saranno difficilmente utilizzabili per lunghi elenchi di file e i problemi sopra menzionati potrebbero portare facilmente a trascurare errori.
pabouk,

1
@pabouk punti positivi; il mondo reale complica sempre le cose e le tue correzioni sono utili. :) Ma penso ancora che questo approccio globale sia il migliore. Se ci sono troppi file per confermare visivamente tutto, puoi | head -20almeno vedere se sembra approssimativamente corretto, mentre se solo rm my_patternnon hai la possibilità di individuare un grosso errore.
Nathan Long,

1
Puoi trovare find per mostrarti i file prima di eliminarli, lasciare fuori il -delete e usare solo find . -type f ! -name "*.pdf"per stampare su console, o pipe su less o un file. [e poi reindirizza a xargs per rm se lo desideri, come i commenti di pabouk (con -print0 | ... -0 per nomi di file strani)]
Xen2050,

3

Solitamente risolvo questi problemi dall'interprete interattivo di Python:

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

Potrebbe essere più lungo di un one-liner con findo xargs, ma è estremamente resistente e so esattamente cosa fa, senza doverlo prima cercare.


Per coloro che ottengono sempre più nervoso, con ogni linea aggiuntiva, abbiamo potuto farne uno:for item in [f for f in os.listdir('.') if not f.endswith('.pdf')]: os.remove(item)
Jacob Vlijm

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,

simpatico! il secondo mi dà un errore di sintassi, non vedo perché.
Jacob Vlijm,

strano; funziona con Python 3.4 e Python 2.7 sul mio sistema.
mic_e

2

una risposta migliore (rispetto alla mia precedente risposta) a questa domanda sarà usando il potente filecomando.

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

ora il tuo 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

il lavoro del forcomando è dare i file nella directory corrente sotto forma di variabile $var. if-thenIl comando genera i nomi dei file pdf prendendo lo stato di uscita 0dal file -i "$var" | grep -q 'application/pdf\;'comando, darà lo stato di uscita 0solo se trova i file pdf.



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

Leggi come, rimuovi tutti i file che non lo sono a.pdfo x.pdf.

Funziona facendo uso di 2 globi estesi, l'esterno !()per negare il glob contenuto che a sua volta richiede che il glob debba corrispondere a uno o più ao xmodelli prima del .pdfsuffisso. Vedi 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

1

modo shell portatile

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

Praticamente POSIX e compatibile con qualsiasi shell stile Bourne ( ksh, bash, dash). Adatto per script portatili e quando non è possibile utilizzare bashil globbing esteso della shell.

perl:

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

O leggermente più pulito:

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

pitone alternativo

python -c 'import os;map(lambda x: os.remove(x), filter(lambda x: not x.endswith(".pdf"),os.listdir(".")))'

0

Fai attenzione a ciò che stai eliminando!

Un modo sicuro per testarlo prima di provare a eliminare è quello di testare prima ls, poiché alcuni comportamenti non rilevati potrebbero eliminare file indesiderati. E puoi farlo direttamente fuori dalla directory. lsè simile a rm, quindi:

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

Questo elencherà

y.zip
z.mp3

E ora puoi vedere cosa stai eliminando e puoi eliminarli in sicurezza:

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

E questo è tutto. Puoi usare i caratteri jolly *per essere più selettivo come conservare solo i documenti del corso di programmazione:

rm sub/path/to/files/!(*programming*)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.