Unterschied zwischen rm my-symlink und rm my-symlink/

Unterschied zwischen rm my-symlink und rm my-symlink/

Ich wollte nur wissen, warum bei meiner Verwendung rm -rf my-symlinknur der symbolische Link gelöscht wird, rm -rf my-symlink/die Dateien im verknüpften Verzeichnis jedoch gelöscht werden und der symbolische Link unverändert bleibt?

Antwort1

Sie können den Unterschied erkennen, indem Sie die Ausgabe von stat my-symlinkund vergleichen stat my-symlink/. my-symlink, ohne Schrägstrich, ist der symbolische Link selbst; my-symlink/, mit Schrägstrich, ist das Verzeichnis, auf das der symbolische Link zeigt. Dies können Sie separat überprüfen, indem Sie die Inodes von und des Verzeichnisses vergleichen, my-symlink/auf das er zeigt.

Mit diesen Informationen in der Hand stimmt das Verhalten, das Sie sehen, mit dem inrm's Spezifikation: Löscht bei der Verarbeitung eines symbolischen Links rmden Link, ohne „hineinzusteigen“, wenn er auf ein Verzeichnis zeigt; bei der Verarbeitung eines Verzeichnisses (mit der -rOption) löscht es dessen Inhalt rekursiv. In diesem my-symlink/Fall rmversucht es zwar, das „Verzeichnis“ zu löschen, schlägt aber fehl, da es sich nicht um ein Verzeichnis, sondern um einen symbolischen Link handelt – aufgrund des -fFlags verursacht dies jedoch keinen Fehler.

Antwort2

Ich dachte, ich würde das Verhalten etwas genauer untersuchen, also hier noch eine Antwort.

Intern rmverwendetFTSzum rekursiven Zugriff auf Dateihierarchien. fts_opennimmt ein Array von Pfaden als Parameter und erstellt für jeden Pfad eine Baumstruktur. Dies ermöglicht dem Programmierer, mehrere Orte nahtlos zu erkunden, als wären sie Teil einer einheitlichen Hierarchie.

Hier ist ein Testprogramm, mit dem Sie selbst mit FTS spielen können.

#include <stdio.h>
#include <stdlib.h>
#include <fts.h>

int main(int argc, char* argv[])
{
    if(argc < 2) return EXIT_FAILURE;

    char* const* arr = argv + 1;
    FTS* hier = fts_open(arr, FTS_NOSTAT | FTS_PHYSICAL, NULL);

    FTSENT* ent;
    while((ent = fts_read(hier))) {
        printf("%s info=%d (D=%d DP=%d F=%d SL=%d)\n",
               ent->fts_accpath, ent->fts_info,
               ent->fts_info == FTS_D, ent->fts_info == FTS_DP,
               ent->fts_info == FTS_F || ent->fts_info == FTS_NSOK,
               ent->fts_info == FTS_SL);
    }

    fts_close(hier);
    return EXIT_SUCCESS;
}

Nehmen wir an, wir haben die folgende Verzeichnisstruktur erstellt:

$ mkdir dir
$ touch dir/file
$ ln -s dir sym

Betrachten wir nun Ihren ersten Fall und sehen wir, wie FTS die Untersuchung durchführt.

$ gcc fts.c 
$ ./a.out sym
sym info=12 (D=0 DP=0 F=0 SL=1)

Wie Sie sehen, symwird in diesem Fall als Datei angesehen. Genauer gesagt als symbolischer Link. Mit diesen Informationen rmwürde es daher als Datei behandelt und aufgerufen unlinkat(AT_FDCWD, "sym", 0). Der letzte Parameter (0) bewirkt, unlinkatdass es sich wie verhält unlink. Mit anderen Worten: Es löscht einfach eine Datei. Infolgedessen verschwindet Ihr Link.

Sehen wir uns nun an, was mit passiert sym/.

$ ./a.out sym/
sym/ info=1 (D=1 DP=0 F=0 SL=0)
file info=11 (D=0 DP=0 F=1 SL=0)
sym/ info=6 (D=0 DP=1 F=0 SL=0)

In diesem Fall symwurde als Zielverzeichnis behandelt. Wir iterieren zuerst zu symund dann sym/filenoch symeinmal. Letzteres liegt an der Funktionsweise von FTS: Zuerst iteriert es über den Inhalt und kehrt dann zum Stammknoten zurück. Das ist eigentlich ziemlich praktisch für rm. Im ersten Durchgang ( D) kann es Dateien löschen und im zweiten ( DP) die leeren Verzeichnisse entfernen.

Wie Sie sehen, meldet sich FTS sym/in beiden Fällen als Verzeichnis. Das liegt daran, dass wir den Pfad mit einem abschließenden Schrägstrich angegeben haben, wodurch der Kernel gezwungen wird, ihn als Verzeichnis zu interpretieren. Im Fall eines Links bedeutet dies, dass er diesem auf jeden Fall folgt.In technischeren Begriffen heißt es in den Spezifikationen:

Ein Pfadname, der mindestens ein Zeichen außer einem Schrägstrich enthält und mit einem oder mehreren abschließenden Schrägstrichen endet, wird so aufgelöst, als ob an den Pfadnamen ein einzelner Punkt ( '.' ) angehängt wäre.

Da FTS sym/als Verzeichnis gemeldet wird, rmverhält es sich, als würde es ein leeres Verzeichnis löschen. Dementsprechend ruft es auf unlinkat(AT_FDCWD, "sym/", AT_REMOVEDIR). Dies führt dazu, unlinkatdass es sich wie verhält rmdir.

sym/Beim Auflösen des Pfads erkennt der Systemaufruf jedoch, unlinkatdass ihm tatsächlich kein Verzeichnis zugewiesen wird. Er wird daher eine Meldung ausgeben ENOTDIR, die Folgendes auslöst:

$ rm: cannot remove ‘sym/’: Not a directory

Und tatsächlich, wenn Sie die Flagge aus Ihren Anrufen entfernen -f... ist das genau das, was Sie sehen werden. Ob dies nun ein Fehler oder ein Feature ist ... ich habe keine Ahnung.

verwandte Informationen