Löschen Sie alle Dateien außer Dateien mit der Endung pdf in einem Verzeichnis

50

Ich habe ein Verzeichnis, das Folgendes enthält:

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

Ich möchte alle Dateien mit Ausnahme von x.pdfund löschen a.pdf. Wie mache ich das vom Terminal aus? Es gibt keine Unterverzeichnisse, daher ist keine Rekursion erforderlich.

Starkers
quelle

Antworten:

63
cd <the directory you want>
find . -type f ! -iname "*.pdf" -delete
  • Mit dem ersten Befehl gelangen Sie in das Verzeichnis, in dem Sie Ihre Dateien löschen möchten
  • Der zweite Befehl löscht alle Dateien mit Ausnahme der Dateien, die mit .pdfDateiname enden

Wenn sich beispielsweise ein Verzeichnis tempin Ihrem privaten Ordner befindet, gehen Sie wie folgt vor :

cd ~/temp

dann Dateien löschen:

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

Dadurch werden alle Dateien außer gelöscht xyz.pdf.

Sie können diese beiden Befehle kombinieren, um:

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

.ist das aktuelle Verzeichnis. !bedeutet, dass alle Dateien außer denen mit .pdfam Ende genommen werden. -type fWählt nur Dateien aus, keine Verzeichnisse. -deletebedeutet, es zu löschen.

HINWEIS: Mit diesem Befehl werden alle Dateien (außer PDF-Dateien, aber auch versteckte Dateien) im aktuellen Verzeichnis sowie in allen Unterverzeichnissen gelöscht. !muss vorher kommen -name. wird einfach -namenur einschließen .pdf, während -inamebeide .pdfund einschließen.PDF

Um nur im aktuellen Verzeichnis und nicht in den Unterverzeichnissen zu löschen, fügen Sie Folgendes hinzu -maxdepth 1:

find . -maxdepth 1 -type f ! -iname "*.pdf" -delete
Edward Torvalds
quelle
Danke für die Antwort. Können Sie mir helfen, die Syntax ein wenig zu verstehen? .bedeutet "und"? !bedeutet "Ausgenommen" -namebedeutet, dass Sie durch einen Namensparameter ausschließen möchten, und ist dann -deletedie Aktion, die beim Auffinden durchzuführen ist? Also sucht es nach allem außer "* .pdf" und löscht sie? Oder habe ich falsch verstanden?
Jessenorton
.bedeutet aktuelles Verzeichnis. !bedeutet, alle Dateien mit Ausnahme der .pdfam Ende. -deletebedeutet, es zu löschen. bin ich jetzt klar
Edward Torvalds
@terdon Starkers sagte, dass es keine Unterverzeichnisse gibt. Ich werde meine Antwort bearbeiten, um breiter zu sein
Edward Torvalds
+1 Sie sollten den -maxdepth 1Parameter enthalten haben, um mit zu beginnen. Dann schlagen Sie vor, den Parameter zu entfernen, falls rekursiv gelöscht werden soll.
Tulains Córdova
3
dies machte mich darauf aufmerksam, dass wir -inameanstelle von verwenden sollten -name, oder Dateien mit .PDFeiner Erweiterung werden durchrutschen.
muru
43

Mit bashder erweiterten Shell-Globbing-Funktion können Sie alle Dateien mit anderen als den .pdfverwendeten Erweiterungen entfernen

rm -- *.!(pdf)

Wie von @pts angegeben, geben die --Zeichen das Ende aller Befehlsoptionen an. Stellen Sie den Befehl in seltenen Fällen sicher, wenn die Namen der Dateien mit einem -Zeichen beginnen.

Wenn Sie Dateien ohne oder mit einer anderen Erweiterung löschen möchten, können Sie .pdf, wie von @DennisWilliamson ausgeführt, diese verwenden

rm -- !(*.pdf)

Erweitertes Globbing sollte standardmäßig aktiviert sein. Wenn dies nicht der Fall ist, können Sie dies mit tun

shopt -s extglob

Insbesondere wenn Sie dies in einem Skript verwenden möchten, ist es wichtig zu beachten, dass der Glob standardmäßig nicht erweitert an den übergeben wird, wenn der Ausdruck mit nichts übereinstimmt (dh wenn sich keine Nicht-PDF-Dateien im Verzeichnis befinden) rmBefehl, was zu einem Fehler wie

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

Sie können dieses Standardverhalten mit der nullglobShell-Option ändern, dies hat jedoch ein eigenes Problem. Eine ausführlichere Diskussion finden Sie in NullGlob - Gregs Wiki

Stahlfahrer
quelle
Besserer Ansatz IMO.
Takkat
Was ist mit Dateien ohne Erweiterung? FWIW, in zsh ist esrm *~*.pdf
Emil Jeřábek
1
Ich würde den Punkt in die Klammern setzen.
Dennis Williamson
4
Ah, der Stern sollte auch innen gehen: !(*.py). Wenn das OP nur ".pdf" -Dateien übrig haben möchte, sollten vermutlich auch Dateien ohne Erweiterungen gelöscht und nicht ignoriert werden.
Dennis Williamson
1
Dieser Ansatz ist einfacher und übersichtlicher als die akzeptierte Antwort.
Peter
18

In den Papierkorb löschen :

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

Oder über mvBefehl (aber auf diese Weise können Sie es nicht aus dem Papierkorb wiederherstellen , da es nicht .trashinfo Informationen aufzeichnen, so dass diese Mittel Sie Ihre Dateien auf ein bewegtes Ziel , wo es ist , wie folgend).

mv !(*.pdf) ~/.local/share/Trash/files
αғsнιη
quelle
6
Dieser Ansatz ist viel sicherer als die direkte Verwendung rm.
Seth
14

Der einfachste Ansatz: Erstellen Sie irgendwo ein anderes Verzeichnis (wenn Sie nur in einem Verzeichnis löschen, nicht rekursiv, kann es sogar ein Unterverzeichnis sein); Bewegen Sie alle PDFs dorthin. alles andere löschen; Schiebe die PDF's zurück; Zwischenverzeichnis löschen.

Schnell und einfach können Sie genau sehen, was Sie tun. Stellen Sie einfach sicher, dass sich das Zwischenverzeichnis auf demselben Gerät befindet wie das Verzeichnis, das Sie bereinigen, damit Verschiebungen Umbenennungen und keine Kopien sind!

Jerry
quelle
4
+1 Nochmals für einen Kommentar, der für den unerfahrenen Benutzer sinnvoll ist und mit ziemlicher Sicherheit nicht dazu führt, dass Dateien versehentlich gelöscht werden.
Trognanders
4

Verwende bashs GLOBIGNORE:

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

Aus der Manpage von bash:

GLOBIGNORE:

            Eine durch Doppelpunkte getrennte Liste von Mustern, die die Menge definieren
            von Dateinamen, die von der Pfadnamenerweiterung ignoriert werden sollen.

Ein kurzer Test:

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

Ausgabe:

y.zip
z.mp3
Cyrus
quelle
3

Sei vorsichtig und komponiere: benutze Xargs

Hier ist ein Ansatz, den ich mag, da ich sehr vorsichtig sein kann: Erstelle einen Weg, um nur die Dateien anzuzeigen, die ich löschen möchte, und sende sie dann an rmusing xargs. Zum Beispiel:

  • ls zeigt mir alles
  • ls | grep pdfZeigt mir die Dateien, die ich behalten möchte. Hmm.
  • ls | grep -v pdfzeigt das gegenteil: alles ausser was ich behalten will. Mit anderen Worten, es wird die Liste der Dinge angezeigt, die ich löschen möchte. Ich kann das bestätigen, bevor ich etwas Gefährliches tue.
  • ls | grep -v pdf | xargs rmsendet genau diese Liste zum rmLöschen an

Wie gesagt, ich mag dies hauptsächlich aus Sicherheitsgründen: kein Zufall rm *für mich. Zwei weitere Vorteile:

  • Es ist zusammensetzbar; Sie können lsoder verwenden find, um die anfängliche Liste zu erhalten. Sie können alles verwenden, was Sie möchten, um diese Liste einzugrenzen - eine andere grep, eine andere awkoder was auch immer. Wenn Sie nur Dateien löschen müssen, deren Namen eine Farbe enthalten, können Sie diese auf dieselbe Weise aufbauen.
  • Sie können jedes Werkzeug für seinen Hauptzweck verwenden. Ich bevorzuge es zu findfinden und rmzu entfernen, anstatt mich daran erinnern zu müssen, dass findeine -deleteFlagge akzeptiert wird . Und wenn Sie dies erneut tun, können Sie alternative Lösungen erstellen. Vielleicht können Sie stattdessen rmeinen trashBefehl erstellen , der die Datei in den Papierkorb verschiebt (undeletion zulässt) und stattdessen an diesen weiterleitet rm. Sie brauchen keine findUnterstützung für diese Option, Sie leiten einfach zu ihr.

Aktualisieren

In den Kommentaren von @pabouk finden Sie Informationen dazu, wie Sie dies ändern können, um einige Randfälle wie Zeilenumbrüche in Dateinamen, Dateinamen my_pdfs.zipusw. zu behandeln.

Nathan Long
quelle
4
Ich habe hier drei Probleme festgestellt: a) Es werden alle Dateien ausgeschlossen, die pdfirgendwo in ihrem Namen enthalten sind. --- b) Es werden PDF-Dateien gelöscht, wenn einer der Buchstaben im Suffix in Großbuchstaben geschrieben ist. --- c) Es ist keine gute Idee, die Ausgabe von zu verwenden ls. Es funktioniert nicht mit Dateinamen, die Zeilenumbrüche enthalten. Einige Implementierungen zum lsErsetzen von Sonderzeichen, z ?. B. tab durch . --- Es ist besser zu nutzen: find -maxdepth 1 -print0. (nicht so kurz wie ls:) ----- Um a) und b) zu lösen, verwenden Sie grep -vi '\.pdf$'--- vollständige (aber nur GNU) Lösung:find -maxdepth 1 -print0 | grep -viz '\.pdf$' | xargs -0 rm
pabouk
1
Ich verstehe, dass Sie die Lösung als "interaktiven" Prozess mit mehreren manuellen Iterationen verstanden haben, aber die Überprüfungen sind für lange Dateilisten kaum verwendbar, und die oben genannten Probleme können leicht dazu führen, dass Fehler übersehen werden.
Pabouk
1
@ Pabouk gute Punkte; Die reale Welt macht die Dinge immer komplizierter, und Ihre Korrekturen sind hilfreich. :) Aber ich denke immer noch, dass dieser allgemeine Ansatz am besten ist. Wenn zu viele Dateien vorhanden sind, um alles visuell zu bestätigen, können Sie | head -20zumindest überprüfen, ob sie ungefähr korrekt aussehen, und wenn Sie dies nur rm my_patterntun, haben Sie keine Chance, einen großen Fehler zu entdecken.
Nathan Long
1
Sie können sich die Dateien von find anzeigen lassen, bevor Sie sie ebenfalls löschen. Lassen Sie das -delete weg und verwenden Sie es einfach find . -type f ! -name "*.pdf", um auf die Konsole zu drucken oder auf less oder eine Datei umzuleiten . [und dann wie in Pabouks Kommentaren (mit -print0 | ... -0 für seltsame Dateinamen) an xargs rm weiterleiten]
Xen2050
3

Normalerweise löse ich solche Probleme mit dem interaktiven Python-Interpreter:

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

Es mag länger sein als ein Einzeiler mit findoder xargs, aber es ist extrem belastbar, und ich weiß genau, was es tut, ohne es zuerst erforschen zu müssen.

Mäuse
quelle
Für diejenigen, die mit jeder zusätzlichen Zeile immer nervöser werden, könnten wir eine daraus machen: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
nett! Der zweite gibt mir einen Syntaxfehler, verstehe nicht warum.
Jacob Vlijm
seltsam; Es funktioniert sowohl mit Python 3.4 als auch mit Python 2.7 auf meinem System.
mic_e
2

Eine bessere Antwort (im Vergleich zu meiner vorherigen Antwort) auf diese Frage ist die Verwendung des leistungsstarken fileBefehls.

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

jetzt dein problem:

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

Die Aufgabe des forBefehls ist es, die Dateien im aktuellen Verzeichnis in Form von Variablen anzugeben $var. if-thenBefehl gibt die Namen von PDF-Dateien aus, indem er den Exit-Status 0von file -i "$var" | grep -q 'application/pdf\;'Befehl annimmt. Er gibt den Exit-Status von 0nur dann an, wenn er PDF-Dateien findet.

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

Warnung! Versuchen Sie es lieber zuerst

ls -l $(ls -lo|grep -v [Pp][Dd][Ff]$|awk '{print $7}')
Martín-Blas Pérez Pinilla
quelle
2
Puh, das ist in vielerlei Hinsicht fehlerhaft: smallo.ruhr.de/award.html#ls , smallo.ruhr.de/award.html#grep , und es ignoriert Dateinamen mit Leerzeichen oder Sonderzeichen völlig.
David Foerster
1
Sie sollten sich wirklich verwenden -imit grepfür Groß- und Kleinschreibung Matching.
muru
1
rm -i -- !(*@(a|x).pdf)

Lesen Sie als, entfernen Sie alle Dateien, die nicht a.pdfoder sind x.pdf.

Dies funktioniert durch die Verwendung von 2 erweitert Klackse machen, die äußere !()die enthaltenen glob negieren , die selbst erfordert , dass die glob eine oder mehrere übereinstimmen müssen aoder xMuster vor dem .pdfSuffix. Siehe 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
quelle
1

tragbare Schale Weg

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

Ziemlich viel POSIX und kompatibel mit jedem Bourne-style - Shell ( ksh, bash, dash). Gut geeignet für portable Skripte und wenn Sie das bashExtended Shell Globbing nicht verwenden können .

perl:

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

Oder etwas sauberer:

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

alternative Python

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

Pass auf, was du löschst!

Ein sicherer Weg, es zu testen, bevor Sie versuchen, es zu löschen, besteht darin, es zuerst mit zu testen ls, da einige nicht erfasste Verhaltensweisen unerwünschte Dateien löschen könnten. Und Sie können dies direkt außerhalb des Verzeichnisses tun. lsist ähnlich wie rm, so:

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

Dies wird aufgelistet

y.zip
z.mp3

Und jetzt können Sie sehen, was Sie löschen und sie sicher löschen:

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

Und das ist es. Sie können Platzhalter verwenden *, um selektiver zu sein, wie z. B. nur Programmierunterlagen aufzubewahren:

rm sub/path/to/files/!(*programming*)
KeitelDOG
quelle