Löschen Sie alle Ordner in einem Ordner mit Ausnahme eines Ordners mit einem bestimmten Namen


16

Ich muss alle Ordner in einem Ordner mithilfe eines täglichen Skripts löschen. Der Ordner für diesen Tag muss verlassen werden.

Der Ordner 'myfolder' hat 3 Unterordner: 'test1', 'test2' und 'test3'. Ich muss alle bis auf 'test2' löschen.

Ich versuche hier den genauen Namen zu finden:

find /home/myfolder -type d ! -name 'test2' | xargs rm -rf

ODER

find /home/myfolder -type d ! -name 'test2' -delete

Dieser Befehl versucht immer auch den Hauptordner 'myfolder' zu löschen! Gibt es eine Möglichkeit, dies zu vermeiden?


6
In Unix und Linux nennen wir diese "Verzeichnisse", nicht "Ordner".
Christ

1
Abhängig von Ihrer Shell müssen Sie möglicherweise diesen !Operator angeben: \!oder '!'.
Toby Speight

Antworten:


31

Dadurch werden alle Ordner innerhalb löschen , ./myfolderaußer dass ./myfolder/test2und alle Inhalte bewahrt werden:

find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?' -delete

Wie es funktioniert

  • find Startet einen Suchbefehl.
  • ./myfolderweist find an, mit dem Verzeichnis ./myfolderund seinem Inhalt zu beginnen.

  • -mindepth 1 nicht, um sich ./myfolderselbst zu entsprechen, nur die Dateien und Verzeichnisse darunter.

  • ! -regex '^./myfolder/test2\(/.*\)?' Weist find an, !alle Dateien oder Verzeichnisse, die mit dem regulären Ausdruck übereinstimmen , auszuschließen ( ) ^./myfolder/test2\(/.*\)?. ^stimmt mit dem Anfang des Pfadnamens überein. Der Ausdruck (/.*\)?entspricht entweder (a) einem Schrägstrich gefolgt von irgendetwas oder (b) überhaupt nichts.

  • -delete weist find an, die übereinstimmenden (dh nicht ausgeschlossenen) Dateien zu löschen.

Beispiel

Stellen Sie sich eine Verzeichnisstruktur vor, die wie folgt aussieht:

$ find ./myfolder
./myfolder
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

Wir können den Befehl find (ohne -delete) ausführen, um zu sehen, was damit übereinstimmt:

$ find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?'
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3

Wir können überprüfen, ob dies funktioniert hat, indem wir uns die verbleibenden Dateien ansehen:

$ find ./myfolder
./myfolder
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

1
Alternative, -pruneum test2/*/Unterverzeichnisse in Ruhe zu lassen: Kehren Sie zu rm -rund fügen Sie hinzu -maxdepth 1.
Toby Speight

@Isaac OK. Erledigt. (Auch +1 für Ihre ausgezeichnete Antwort.)
John1024

Ausgezeichnete Arbeit !, aber leider: das alle entfernen werden Dateien innerhalb ./myfolder. Sie benötigen ein fehlendes (IMvhO) nur-type d für Verzeichnisse .
Isaac

Ok, das sollte funktionieren, wie Sie wollen:find ./myfolder -depth -mindepth 1 -maxdepth 1 -type d ! -regex '^./myfolder/test2\(/.*\)?'
Isaac

10

Bash benutzen :

shopt -s extglob
rm -r myfolder/!(test2)/

Beispiel:

$ tree myfolder/
myfolder/
├── test1
│   └── file1
├── test2
│   └── file2
└── test3
    └── file3

$ echo rm -r myfolder/!(test2)
rm -r myfolder/test1 myfolder/test3
$ rm -r myfolder/!(test2)
$ tree myfolder/
myfolder/
└── test2
    └── file2

1 directory, 1 file

5

tl; dr

find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 \
     -exec echo rm -rf '{}' \;

Entfernen Sie das Echo, wenn Sie mit der Liste der Dateien zufrieden sind.


Mit -mindepth 1wird sichergestellt, dass das oberste Verzeichnis nicht ausgewählt ist.

$ find ./myfolder -mindepth 1 -type d
./myfolder/test2
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Aber Subdirs im Inneren -not -name test2werden nicht vermieden test2:

$ find ./myfolder -mindepth 1 -type d -not -name 'test2'
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Um das zu tun, brauchst du so etwas wie Prune:

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Aber nicht verwenden delete, wie es impliziert depthund das wird vom längsten Weg zu löschen beginnen:

$ find ./myfolder -depth -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test/a1/a2/a3
./myfolder/test/a1/a2
./myfolder/test/a1
./myfolder/test

Verwenden Sie entweder rm -rf(entfernen Sie das, echowenn Sie tatsächlich löschen möchten):

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test
rm -rf ./myfolder/test/a1
rm -rf ./myfolder/test/a1/a2
rm -rf ./myfolder/test/a1/a2/a3

Oder verwenden Sie auch , maxdepthwenn Sie nur Verzeichnisse (und alles darin) echolöschen müssen (entfernen Sie das, um es tatsächlich zu löschen):

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test

A -deleteschlägt immer noch fehl, wenn das Verzeichnis nicht leer ist:

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -delete
find: cannot delete ‘./myfolder/test’: Directory not empty

2

Wenn Sie zsh verwenden, können Sie:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2

0

Getestet mit dem folgenden Befehl und es hat gut funktioniert

find  /home/myfolder -maxdepth 1 -type d ! -iname test2 -exec rm -rvf {} \;

Sie haben das gleiche Problem wie beim OP; Das Auflisten von / home / folder in der Befehlszeile (ohne das Kritische -mindepth 1) bewirkt, dass das oberste Verzeichnis allen Kriterien entspricht (es ist ein Verzeichnis und heißt nicht "test2") und wird daher gelöscht.
Jeff Schaller
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.