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?

Riju Mahna
quelle
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
John1024
quelle
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
Jeff Schaller
quelle
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
Isaac
quelle
2

Wenn Sie zsh verwenden, können Sie:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2
JoL
quelle
0

Getestet mit dem folgenden Befehl und es hat gut funktioniert

find  /home/myfolder -maxdepth 1 -type d ! -iname test2 -exec rm -rvf {} \;
Praveen Kumar BS
quelle
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