Es gibt zwei Möglichkeiten, diese Frage zu lesen, und die vorhandenen Antworten decken beide Interpretationen ab: BEIDES: (a) Dateien mit den angegebenen Namen direkt im Zielverzeichnis beibehalten und - wie rm -rimpliziert - alles andere löschen, einschließlich Unterverzeichnisse - auch wenn sie enthalten Dateien mit den angegebenen Namen; ODER: (b) den gesamten Teilbaum des Zielverzeichnisses durchlaufen und in jedem Verzeichnis alle Dateien außer denen mit den aufgeführten Namen löschen.
mklement0
Antworten:
219
find [path]-type f -not -name 'textfile.txt'-not -name 'backup.tar.gz'-delete
Wenn Sie -type ffind nicht angeben , werden auch Verzeichnisse aufgelistet, die Sie möglicherweise nicht möchten.
Oder eine allgemeinere Lösung mit der sehr nützlichen Kombination find | xargs:
Ich erhalte "Syntaxfehler in der Nähe eines unerwarteten Tokens" ("), wenn ich das tue shopt -s extglob; rm -rf !(README|LICENSE). Irgendeine Idee warum?
Dennis
@nic Ich erinnere mich nicht, sorry. Ich habe wahrscheinlich finddie -deleteOption verwendet.
Dennis
Dies ist die beste Lösung für mich und sie funktioniert standardmäßig auf meinem Ubuntu 12.04.4 LTS, ohne dass shopt
xtian
3
@nic, @Dennis: Der Syntaxfehler deutet darauf hin, dass etwas ANDERES als bashverwendet wurde, z. B. dashwo extglobes nicht unterstützt wird. In einer interaktivenbash Shell funktioniert der Befehl jedoch AUCH aus verschiedenen Gründen nicht wie angegeben. Kurz gesagt: shopt -s extglobBY ITSELF ausführen ; EINMAL ERFOLGREICH AKTIVIERT (überprüfen mit shopt extglob), ausführen rm -rf !(README|LICENSE). (Obwohl extglobes noch nicht aktiviert ist, !(...)wird es durch Verlaufserweiterung ausgewertet , BEVOR die Befehle ausgeführt werden. Da dies wahrscheinlich fehlschlägt, wird NIEMALS der Befehl ausgeführt und extglobnie
aktiviert
2
@nic, @Dennis, @ mklement0: Ich hatte das gleiche Problem mit "Syntaxfehler in der Nähe eines unerwarteten Tokens (", wenn der Befehl in einer .sh-Datei (#! / bin / bash) ausgeführt wurde, aber nicht, als ich ihn in einem Befehl ausführte Zeilenschnittstelle. Es stellte sich heraus, dass shopt -s extglobich zusätzlich zu der Ausführung in der Befehlszeilenschnittstelle diese in meiner Skriptdatei erneut ausführen musste. Dies löste das Problem für mich.
Dadurch werden alle Dateien im aktuellen Verzeichnis aufgelistet, dann alle Dateien aufgelistet, die nicht Ihren Kriterien entsprechen (achten Sie darauf, dass sie mit den Verzeichnisnamen übereinstimmen), und sie werden dann entfernt.
Update : Wenn Sie basierend auf Ihrer Bearbeitung wirklich alles aus dem aktuellen Verzeichnis löschen möchten, außer den von Ihnen aufgelisteten Dateien, kann dies verwendet werden:
Es wird ein Sicherungsverzeichnis erstellt /tmp_backup(Sie haben Root-Rechte, oder?), Die aufgelisteten Dateien in dieses Verzeichnis verschieben, alles im aktuellen Verzeichnis rekursiv löschen (Sie wissen, dass Sie sich im richtigen Verzeichnis befinden, oder?), Verschieben zurück zum aktuellen Verzeichnis alles aus /tmp_backupund schließlich löschen /tmp_backup.
Ich wähle das Sicherungsverzeichnis im Stammverzeichnis aus, denn wenn Sie versuchen, alles rekursiv aus dem Stammverzeichnis zu löschen, hat Ihr System große Probleme.
Sicher gibt es elegantere Möglichkeiten, dies zu tun, aber diese ist ziemlich einfach.
Funktioniert auch sehr gut mit egrep, zB zum Reinigen von Latex-Zwischenfeilen:find . | egrep -v "\.tex|\.bib" | xargs rm
mtsz
erstaunlicher Befehl! Zum Entfernen von Verzeichnissen wechseln Sie einfach zu rm -r
Aris
1
Wenn Sie einfach alles im aktuellen Verzeichnis außer den ausgeschlossenen Kriterien löschen möchten: Funktioniert find . -maxdepth 1 | grep -v "exclude these" | xargs rm -rviel schneller, da kein unnötiger Drilldown in Verzeichnisse erforderlich ist.
Billynoah
Re- findPipeline: Abgesehen von Effizienzproblemen (3 Befehle werden für das verwendet, was findalleine möglich ist) funktioniert dies bei Dateinamen mit eingebetteten Leerzeichen nicht wie beabsichtigt und löscht möglicherweise die falschen Dateien.
mklement0
Ein Befehl, der "zu speichernde" Dateien an einem anderen Speicherort ( /tmp_backup) speichert, endet nicht gut, wenn er unterbrochen wird. Aus Sicht des Benutzers sind alle Dateien verschwunden, es sei denn, er weiß, wo er sie suchen muss, um sie zurückzubekommen . Aus diesem Grund bin ich nicht für diese Art von Strategie.
Craig McQueen
20
Angenommen, Dateien mit diesen Namen befinden sich an mehreren Stellen in der Verzeichnisstruktur und Sie möchten alle beibehalten:
find .-type f !-regex ".*/\(textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt\)"-delete
Wenn Sie GLOBIGNORE so einstellen, werden PHP und SQL von Platzhaltern ignoriert, die wie "ls *" oder "rm *" verwendet werden. Wenn Sie also nach dem Festlegen der Variablen "rm *" verwenden, werden nur die Dateien txt und tar.gz gelöscht.
+1; Eine einfachere Alternative zum Festlegen und Wiederherstellen der GLOBIGNOREVariablen ist die Verwendung einer Unterschale:(GLOBIGNORE='*.php:*.sql'; rm *)
mklement0
19
Ich bevorzuge die Verwendung einer Unterabfrageliste:
Dies ist komplizierter, da Sie sich um die Berechtigungen kümmern müssen, nachdem Sie sie zurückkopiert haben.
Romulus
2
@RemusAvram Sie können geeignete Switches mit cpoder verwenden rsync, um Berechtigungen beizubehalten . Auf jeden Fall ist dies nur eine alternative Methode (als Vorschlag angegeben), die hier ihren Platz als Antwort auf das OP hat.
gniourf_gniourf
Dies ist in vielen Situationen, in denen die aufzubewahrenden Dateien aktiv von anderen Prozessen verwendet werden, möglicherweise nicht angemessen. Es ist auch umständlich, dass die zu entfernenden Dateien nur eine kleine Teilmenge sind und eine große Anzahl von Dateien beteiligt ist.
Codeforester
@codeforester: sicher. Aber es gibt Situationen, in denen es angemessen ist ... tatsächlich verstehe ich den Sinn Ihres Kommentars nicht wirklich :).
gniourf_gniourf
6
Sie können eine for-Schleife dafür schreiben ...%)
for x in*doif["$x"!="exclude_criteria"]then
rm -f $x;fidone;
Ein bisschen spät für das OP, aber hoffentlich nützlich für alle, die viel später per Google hierher kommen ...
Ich fand die Antwort von @awi und den Kommentar zu -delete von @Jamie Bullock wirklich nützlich. Ein einfaches Dienstprogramm, mit dem Sie dies in verschiedenen Verzeichnissen tun können, wobei jedes Mal unterschiedliche Dateinamen / -typen mit minimaler Eingabe ignoriert werden:
rm_except (oder wie auch immer Sie es benennen möchten)
aber Namen mit Leerzeichen sind (wie immer) hart. Versuchte auch mit Virtualbox\ VMsstattdessen die Anführungszeichen. Es löscht immer dieses Verzeichnis ( Virtualbox VMs).
Funktioniert NICHT für Dateien. rm !(myfile.txt)entfernt alle einschließlichmyfile.txt
khaverim
sollte shopt -s extglobzuerst ausgeführt werden, wie @ pl1nk hervorhob
zhuguowei
Ja, es ist sehr wichtig , aktivieren Sie das Extended Globbing ( extglob ) in bash, ich dies in einer täglichen Routine Grundlage tue, über ein paar Macs in Labors: shopt -s extglobund dann cd /Users/alumno/und schließlich rm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library) lesen , erweiterte Globbing hier
juanfal
4
Gerade:
rm $(ls -I "*.txt")#Deletes file type except *.txt
Durchlaufen Sie anschließend alle Dateien in dem Verzeichnis, das Sie ausschließen möchten, und prüfen Sie, ob sich der Dateiname in dem Array befindet, das Sie nicht ausschließen möchten. Wenn dies nicht der Fall ist, löschen Sie die Datei.
for file in*;doif[[!" ${files[@]} "~="$file"]];then
rm "$file"fidone
Der Regex-Vergleich ist falsch - es werden alle Dateien beibehalten, deren Name eine Teilzeichenfolge einer der geschützten Dateien ist (obwohl die umgebenden Leerzeichen dies etwas abschwächen; Dateinamen können jedoch Leerzeichen enthalten). Sie sollten ein Array aller Dateien sammeln, dann die Dateien subtrahieren, die Sie von diesem Array ausschließen möchten, und dann die verbleibenden Dateien entfernen.
Tripleee
-1
Da dies noch niemand erwähnt hat, in einem bestimmten Fall:
OLD_FILES=`echo *`... create new files ...
rm -r $OLD_FILES
(oder einfach rm $OLD_FILES)
oder
OLD_FILES=`ls *`... create new files ...
rm -r $OLD_FILES
Möglicherweise müssen Sie Folgendes verwenden, shopt -s nullglobwenn einige Dateien vorhanden sind oder nicht:
Die bestehende Antwort von Leonardo Hermoso macht dies mit weniger Fehlern. Dies schlägt bei Dateinamen mit Leerzeichen fehl. Die Verwendung eines Arrays löst dieses spezielle Problem auf elegante Weise (und vermeidet auch weniger entscheidend die Verwendung von Großbuchstaben für seine privaten Variablen, was im Allgemeinen vermieden werden sollte).
Tripleee
-3
Anstatt einen direkten Befehl auszuführen, verschieben Sie bitte die erforderlichen Dateien in ein temporäres Verzeichnis außerhalb des aktuellen Verzeichnisses. Löschen Sie dann alle Dateien mit rm *oder rm -r *.
Verschieben Sie dann die erforderlichen Dateien in das aktuelle Verzeichnis.
Dies ist in vielen Situationen, in denen die aufzubewahrenden Dateien aktiv von anderen Prozessen verwendet werden, möglicherweise nicht angemessen. Es ist auch umständlich, dass die zu entfernenden Dateien nur eine kleine Teilmenge sind und eine große Anzahl von Dateien beteiligt ist.
Codeforester
-3
Entfernen Sie alles außer file.name:
ls -d /path/to/your/files/*|grep -v file.name|xargs rm -rf
Dies schlägt schrecklich fehl und kann zu Datenverlust führen, wenn Ihr Verzeichnis / Ihre Dateien Leerzeichen oder ungewöhnliche Zeichen enthalten. Sie sollten niemals ls analysieren. mywiki.wooledge.org/ParsingLs
rm -r
impliziert - alles andere löschen, einschließlich Unterverzeichnisse - auch wenn sie enthalten Dateien mit den angegebenen Namen; ODER: (b) den gesamten Teilbaum des Zielverzeichnisses durchlaufen und in jedem Verzeichnis alle Dateien außer denen mit den aufgeführten Namen löschen.Antworten:
Wenn Sie
-type f
find nicht angeben , werden auch Verzeichnisse aufgelistet, die Sie möglicherweise nicht möchten.Oder eine allgemeinere Lösung mit der sehr nützlichen Kombination
find | xargs
:Löschen Sie beispielsweise alle Nicht-TXT-Dateien im aktuellen Verzeichnis:
Die Kombination
print0
und-0
wird benötigt, wenn in einem der Dateinamen Leerzeichen vorhanden sind, die gelöscht werden sollen.quelle
find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
-print0 | xargs -0 rm --
können Sie nur-delete
Das Extglob (Extended Pattern Matching) muss in BASH aktiviert sein (falls es nicht aktiviert ist):
quelle
shopt -s extglob; rm -rf !(README|LICENSE)
. Irgendeine Idee warum?find
die-delete
Option verwendet.bash
verwendet wurde, z. B.dash
woextglob
es nicht unterstützt wird. In einer interaktivenbash
Shell funktioniert der Befehl jedoch AUCH aus verschiedenen Gründen nicht wie angegeben. Kurz gesagt:shopt -s extglob
BY ITSELF ausführen ; EINMAL ERFOLGREICH AKTIVIERT (überprüfen mitshopt extglob
), ausführenrm -rf !(README|LICENSE)
. (Obwohlextglob
es noch nicht aktiviert ist,!(...)
wird es durch Verlaufserweiterung ausgewertet , BEVOR die Befehle ausgeführt werden. Da dies wahrscheinlich fehlschlägt, wird NIEMALS der Befehl ausgeführt undextglob
nieshopt -s extglob
ich zusätzlich zu der Ausführung in der Befehlszeilenschnittstelle diese in meiner Skriptdatei erneut ausführen musste. Dies löste das Problem für mich.find . | grep -v "excluded files criteria" | xargs rm
Dadurch werden alle Dateien im aktuellen Verzeichnis aufgelistet, dann alle Dateien aufgelistet, die nicht Ihren Kriterien entsprechen (achten Sie darauf, dass sie mit den Verzeichnisnamen übereinstimmen), und sie werden dann entfernt.
Update : Wenn Sie basierend auf Ihrer Bearbeitung wirklich alles aus dem aktuellen Verzeichnis löschen möchten, außer den von Ihnen aufgelisteten Dateien, kann dies verwendet werden:
Es wird ein Sicherungsverzeichnis erstellt
/tmp_backup
(Sie haben Root-Rechte, oder?), Die aufgelisteten Dateien in dieses Verzeichnis verschieben, alles im aktuellen Verzeichnis rekursiv löschen (Sie wissen, dass Sie sich im richtigen Verzeichnis befinden, oder?), Verschieben zurück zum aktuellen Verzeichnis alles aus/tmp_backup
und schließlich löschen/tmp_backup
.Ich wähle das Sicherungsverzeichnis im Stammverzeichnis aus, denn wenn Sie versuchen, alles rekursiv aus dem Stammverzeichnis zu löschen, hat Ihr System große Probleme.
Sicher gibt es elegantere Möglichkeiten, dies zu tun, aber diese ist ziemlich einfach.
quelle
find . | egrep -v "\.tex|\.bib" | xargs rm
find . -maxdepth 1 | grep -v "exclude these" | xargs rm -r
viel schneller, da kein unnötiger Drilldown in Verzeichnisse erforderlich ist.find
Pipeline: Abgesehen von Effizienzproblemen (3 Befehle werden für das verwendet, wasfind
alleine möglich ist) funktioniert dies bei Dateinamen mit eingebetteten Leerzeichen nicht wie beabsichtigt und löscht möglicherweise die falschen Dateien./tmp_backup
) speichert, endet nicht gut, wenn er unterbrochen wird. Aus Sicht des Benutzers sind alle Dateien verschwunden, es sei denn, er weiß, wo er sie suchen muss, um sie zurückzubekommen . Aus diesem Grund bin ich nicht für diese Art von Strategie.Angenommen, Dateien mit diesen Namen befinden sich an mehreren Stellen in der Verzeichnisstruktur und Sie möchten alle beibehalten:
quelle
Sie können die Umgebungsvariable GLOBIGNORE in Bash verwenden.
Angenommen, Sie möchten alle Dateien außer PHP und SQL löschen, dann können Sie Folgendes tun:
Wenn Sie GLOBIGNORE so einstellen, werden PHP und SQL von Platzhaltern ignoriert, die wie "ls *" oder "rm *" verwendet werden. Wenn Sie also nach dem Festlegen der Variablen "rm *" verwenden, werden nur die Dateien txt und tar.gz gelöscht.
quelle
GLOBIGNORE
Variablen ist die Verwendung einer Unterschale:(GLOBIGNORE='*.php:*.sql'; rm *)
Ich bevorzuge die Verwendung einer Unterabfrageliste:
quelle
Da hat es niemand erwähnt:
quelle
cp
oder verwendenrsync
, um Berechtigungen beizubehalten . Auf jeden Fall ist dies nur eine alternative Methode (als Vorschlag angegeben), die hier ihren Platz als Antwort auf das OP hat.:)
.Sie können eine for-Schleife dafür schreiben ...%)
quelle
Ein bisschen spät für das OP, aber hoffentlich nützlich für alle, die viel später per Google hierher kommen ...
Ich fand die Antwort von @awi und den Kommentar zu -delete von @Jamie Bullock wirklich nützlich. Ein einfaches Dienstprogramm, mit dem Sie dies in verschiedenen Verzeichnissen tun können, wobei jedes Mal unterschiedliche Dateinamen / -typen mit minimaler Eingabe ignoriert werden:
rm_except (oder wie auch immer Sie es benennen möchten)
zB um alles außer Textdateien und foo.bar zu löschen:
Ähnlich wie @mishunika, jedoch ohne die if-Klausel.
quelle
Wenn Sie verwenden,
zsh
was ich sehr empfehlen.Mit
extended_glob
quelle
Der Versuch funktionierte mit:
aber Namen mit Leerzeichen sind (wie immer) hart. Versuchte auch mit
Virtualbox\ VMs
stattdessen die Anführungszeichen. Es löscht immer dieses Verzeichnis (Virtualbox VMs
).quelle
rm !(myfile.txt)
entfernt alle einschließlichmyfile.txt
shopt -s extglob
zuerst ausgeführt werden, wie @ pl1nk hervorhobshopt -s extglob
und danncd /Users/alumno/
und schließlichrm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library)
lesen , erweiterte Globbing hierGerade:
Oder:
quelle
ls
Ausgabe kann zu einem Problem werden. Siehe hier für weitere Informationen.Machen Sie die Dateien unveränderlich. Nicht einmal root darf sie löschen.
Alle anderen Dateien wurden gelöscht.
Schließlich können Sie sie veränderlich zurücksetzen.
quelle
Dies ähnelt dem Kommentar von @ siwei-shen, aber Sie benötigen das
-o
Flag, um mehrere Muster zu erstellen . Die-o
Flagge steht für 'oder'find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm
quelle
Sie können dies mit zwei Befehlssequenzen tun. Definieren Sie zunächst ein Array mit dem Namen der Dateien, die Sie nicht ausschließen möchten:
Durchlaufen Sie anschließend alle Dateien in dem Verzeichnis, das Sie ausschließen möchten, und prüfen Sie, ob sich der Dateiname in dem Array befindet, das Sie nicht ausschließen möchten. Wenn dies nicht der Fall ist, löschen Sie die Datei.
quelle
Da dies noch niemand erwähnt hat, in einem bestimmten Fall:
(oder einfach
rm $OLD_FILES
)oder
Möglicherweise müssen Sie Folgendes verwenden,
shopt -s nullglob
wenn einige Dateien vorhanden sind oder nicht:ohne nullglob
echo *.sh *.bash
kann Ihnen "a.sh b.sh * .bash" geben.(Nachdem ich das alles gesagt habe, bevorzuge ich selbst diese Antwort , obwohl sie unter OSX nicht funktioniert.)
quelle
Anstatt einen direkten Befehl auszuführen, verschieben Sie bitte die erforderlichen Dateien in ein temporäres Verzeichnis außerhalb des aktuellen Verzeichnisses. Löschen Sie dann alle Dateien mit
rm *
oderrm -r *
.Verschieben Sie dann die erforderlichen Dateien in das aktuelle Verzeichnis.
quelle
Entfernen Sie alles außer file.name:
quelle