Warum erzeugt der Befehl „find -type d -exec rmdir {} \;“ die Meldung „Datei oder Verzeichnis nicht vorhanden“

Warum erzeugt der Befehl „find -type d -exec rmdir {} \;“ die Meldung „Datei oder Verzeichnis nicht vorhanden“

Zu Testzwecken habe ich folgende Verzeichnisse erstellt.

user@linux:~$ mkdir dir0{1..3}

user@linux:~$ ls -l
total 12K
drwxr-xr-x 2 user user 4.0K Mei  31 10:45 dir01
drwxr-xr-x 2 user user 4.0K Mei  31 10:45 dir02
drwxr-xr-x 2 user user 4.0K Mei  31 10:45 dir03
user@linux:~$ 

Dann entfernte ich es mitfind -exec

user@linux:~$ find -type d -exec rmdir {} \;
rmdir: failed to remove '.': Invalid argument
find: ‘./dir02’: No such file or directory
find: ‘./dir01’: No such file or directory
find: ‘./dir03’: No such file or directory
user@linux:~$ 

Die Verzeichnisse wurden entfernt, ich habe es überprüft.

user@linux:~$ ls -l
total 0
user@linux:~$ 

Meine Fragen sind:

1) Ich verstehe nicht, warum die Nachrichten da waren. Irgendeine Idee, warum?

rmdir: failed to remove '.': Invalid argument
find: ‘./dir02’: No such file or directory

Ich sehe diese Art von Fehler nicht beirmdir

user@linux:~$ mkdir dir0{1..3}
user@linux:~$ 

user@linux:~$ ls -l
total 12K
drwxr-xr-x 2 user user 4.0K Mei  31 22:58 dir01
drwxr-xr-x 2 user user 4.0K Mei  31 22:58 dir02
drwxr-xr-x 2 user user 4.0K Mei  31 22:58 dir03
user@linux:~$ 

user@linux:~$ rmdir *
user@linux:~$ 

user@linux:~$ ls -l
total 0
user@linux:~$ 

2) Ist es möglich, diese Nachrichten zu entfernen?

Antwort1

Sie erhalten die Fehlermeldung „Keine solche Datei oder kein solches Verzeichnis“, findweil findversucht wird, Verzeichnisse zu öffnen, die gerade entfernt wurden. Standardmäßig werden die Aktionen auf alle übereinstimmenden Elemente im aktuell besuchten Verzeichnis angewendet, bevor mit den Unterverzeichnissen fortgefahren wird.

Fügen Sie -depthdem Aufruf von hinzu, dass eine Tiefensuche in den Suchpfaden durchgeführt wird. Dies bedeutet wiederum, dass bei der Ausführung findin einem Verzeichnis dieses bereits besucht wurde und kein erneuter Versuch unternommen wird, es zu besuchen.findrmdir

Aus diesem Grund ist die -depthOption bei der Verwendung implizit (in Implementierungen davon hat ).-deletefind-delete

find . -depth -type d -exec rmdir {} \;

-depthist eine Standardoption für das findDienstprogramm.

Beachten Sie, dass dies rmdirnur bei leeren Verzeichnissen funktioniert. Wenn Sie viele nicht leere Verzeichnisse haben, würde der obige Befehl viele Fehlermeldungen erzeugen.

Verwenden Sie stattdessen (sofern Ihr findSystem dies unterstützt) Folgendes -empty:

find . -type d -empty -delete

Dadurch würden leere Verzeichnisse gelöscht.

Mit einem , das weder finddas Nicht-Standard-Noch hat :-delete-emtpy

find . -depth -type d -exec sh -c '
    for dirpath do
        set -- "$dirpath"/*
        [ ! -e "$1" ] && rmdir "$dirpath"
    done' sh {} +

Dadurch wird geprüft, ob die gefundenen Verzeichnisse leer sind. Wenn dies der Fall ist, werden sie gelöscht.

Das ist ein langer Codeabschnitt, um Fehlermeldungen zu vermeiden, die auftreten, wenn Verzeichnisse nicht leer sind. Alle Fehlermeldungen, dieSindDie erzeugten Ergebnisse werden hoffentlich interessanter anzusehen sein, da es sich wahrscheinlich um „Zugriff verweigert“-Fehler handelt. Die Umleitung der Fehler /dev/nullim ersten findBefehl oben hätte solche Fehler ausgeblendet.

Antwort2

Was vermutlich passiert, ist, dass -exec ... \;find mit der Konstruktion seine Arbeit Schritt für Schritt erledigt:

  • Gehen Sie durch den Verzeichnisbaum und suchen Sie nach Einträgen, die übereinstimmen -type d, und
  • rmdirFühren Sie diese Schritte aus, um die Einträge sofort nach deren Entdeckung auszuführen .

Dies bedeutet, dass in Ihrem Beispiel „find“ nach sucht dir01, es als Verzeichnis für den späteren Zugriff im Hinterkopf behält, rmdires dann ausführt und dann beim Versuch, rekursiv in zu gelangen dir01, einen Fehler ausführt, weil es nicht mehr existiert.

In diesem Fall sollte die Ausführung mit -exec rmdir {} +hilfreich sein: Es rmdir dir01 dir02 dir03wird ein einzelner Aufruf von ausgegeben. Dadurch werden die letzten drei Fehlermeldungen entfernt.

Die Fehlermeldung .wird angezeigt, weil .das aktuelle Verzeichnis zwar ein Verzeichnis ist, aber nicht rmdirgelöscht werden kann, da es nicht leer ist. Verwenden Sie , -min-depthum die Berücksichtigung zu beenden, indem Sie den Befehl ausführen:

find -mindepth 1 -type d -exec rmdir {} +

Dies ist nicht perfekt; verschachtelte Verzeichnisse oder eine große Anzahl übereinstimmender Verzeichnisse können immer noch dazu führen, dass Fehlermeldungen ausgegeben werden, aber im einfachen Fall aus der Frage sollte dies funktionieren.

verwandte Informationen