Diferencia entre rm my-symlink y rm my-symlink/

Diferencia entre rm my-symlink y rm my-symlink/

Solo quería saber por qué si rm -rf my-symlinklo uso, elimina solo el enlace simbólico pero rm -rf my-symlink/elimina los archivos dentro del directorio vinculado y deja el enlace simbólico solo.

Respuesta1

Puede ver la diferencia comparando la salida de stat my-symlinky stat my-symlink/. my-symlink, sin la barra, es el enlace simbólico en sí; my-symlink/, con la barra diagonal, es el directorio al que apunta el enlace simbólico, que puede verificar por separado comparando los inodos del my-symlink/directorio al que apunta.

Con esa información en la mano, el comportamiento que estás viendo coincide con el descrito enrmespecificaciones: al procesar un enlace simbólico, rmelimina el enlace sin descender “dentro” de él si apunta a un directorio; al procesar un directorio (con la -ropción), elimina su contenido de forma recursiva. En este my-symlink/caso, rmintenta eliminar el "directorio", pero falla porque no es un directorio sino un enlace simbólico; sin embargo, debido a la -fbandera, esto no causa un error.

Respuesta2

Pensé en investigar un poco más el comportamiento, así que aquí hay otra respuesta.

Internamente, rmutilizaFTSa recursivo en jerarquías de archivos. fts_opentoma una serie de rutas como parámetro y crea una estructura de árbol para cada ruta. Esto permite al programador explorar varias ubicaciones aparentemente como si fueran parte de una jerarquía unificada.

Aquí tienes un programa de prueba que puedes utilizar para jugar con FTS tú mismo.

#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;
}

Supongamos que hemos creado la siguiente estructura de directorios:

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

Ahora, consideremos su primer caso y veamos cómo FTS lidera la exploración.

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

Como puedes ver, en este caso, symse ve como un archivo. Un enlace simbólico, para ser más exactos. Con esta información, rmpor lo tanto, lo trataríamos como un archivo y lo llamaríamos unlinkat(AT_FDCWD, "sym", 0). El último parámetro (0) hace unlinkatque se comporte como unlink. En otras palabras: simplemente elimina un archivo. Como resultado, su enlace desaparece.

Ahora, echemos un vistazo a lo que sucede con 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)

En este caso, symse trató como su directorio de destino. Primero iteramos hasta symy sym/fileluego symnuevamente. Esto último se debe a cómo funciona FTS: primero, itera sobre el contenido y luego regresa al nodo raíz. En realidad, esto es bastante conveniente para rm. En la primera pasada ( D), puede borrar archivos y en la segunda ( DP) eliminar los directorios vacíos.

Como puede ver, en este caso, FTS informa sym/como un directorio en ambos casos. Esto se debe a que le dimos a la ruta una barra diagonal, lo que obliga al kernel a interpretarla como un directorio. En el caso de un enlace, esto significa que lo seguirá pase lo que pase.En términos más técnicos, las especificaciones dicen:

Un nombre de ruta que contenga al menos un carácter que no sea una barra y que termine con una o más barras diagonales finales se resolverá como si se agregara un carácter de un solo punto ( '.' ) al nombre de ruta.

Debido a que FTS informa sym/como un directorio, rmse comporta como si estuviera eliminando un directorio vacío. En consecuencia, llama unlinkat(AT_FDCWD, "sym/", AT_REMOVEDIR). Esto hace unlinkatque se comporte como rmdir.

Sin embargo, al resolver la sym/ruta, la unlinkatllamada al sistema se dará cuenta de que, en realidad, no se le está asignando un directorio. Por lo tanto, informará ENOTDIR, lo que desencadena:

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

Y de hecho, si eliminas la -fbandera de tus llamadas... Eso es exactamente lo que verás. Ahora bien, si esto es o no un error o una característica... no tengo idea.

información relacionada