Yo esperaría
find . -delete
para eliminar el directorio actual, pero no lo hace. Por qué no?
find . -print
.
cd ..; rm -r dir
con otro caparazón con una semántica bastante clara ...
Yo esperaría
find . -delete
para eliminar el directorio actual, pero no lo hace. Por qué no?
find . -print
.
cd ..; rm -r dir
con otro caparazón con una semántica bastante clara ...
Respuestas:
Los miembros de lo findutils
saben , es compatible con * BSD:
Una de las razones por las que omitimos la eliminación de "." es por compatibilidad con * BSD, donde se originó esta acción.
Las NOTICIAS en el código fuente de findutils muestran que decidieron mantener el comportamiento:
#20802: If -delete fails, find's exit status will now be non-zero. However, find still skips trying to delete ".".
[ACTUALIZAR]
Dado que esta pregunta se convirtió en uno de los temas candentes, me sumergí en el código fuente de FreeBSD y salí a la luz por una razón más convincente.
Veamos el código fuente de la utilidad de búsqueda de FreeBSD :
int
f_delete(PLAN *plan __unused, FTSENT *entry)
{
/* ignore these from fts */
if (strcmp(entry->fts_accpath, ".") == 0 ||
strcmp(entry->fts_accpath, "..") == 0)
return 1;
...
/* rmdir directories, unlink everything else */
if (S_ISDIR(entry->fts_statp->st_mode)) {
if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
warn("-delete: rmdir(%s)", entry->fts_path);
} else {
if (unlink(entry->fts_accpath) < 0)
warn("-delete: unlink(%s)", entry->fts_path);
}
...
Como puede ver, si no filtra punto y punto-punto, alcanzará la rmdir()
función C definida por POSIX unistd.h
.
Haga una prueba simple, rmdir con argumento punto / punto-punto devolverá -1:
printf("%d\n", rmdir(".."));
Echemos un vistazo a cómo POSIX describe rmdir :
Si el argumento de ruta se refiere a una ruta cuyo componente final es punto o punto-punto, rmdir () fallará.
No se dio ninguna razón por qué shall fail
.
Encontré rename
explicar algunas razones :
Cambiar el nombre de punto o punto-punto está prohibido para evitar rutas cíclicas del sistema de archivos.
¿Rutas cíclicas del sistema de archivos ?
Miro el lenguaje de programación C (2da edición) y busco el tema del directorio, sorprendentemente encontré que el código es similar :
if(strcmp(dp->name,".") == 0 || strcmp(dp->name,"..") == 0)
continue;
Y el comentario!
Cada directorio siempre contiene entradas para sí mismo, llamadas ".", Y su padre, ".."; se deben omitir o el programa se repetirá para siempre .
"bucle para siempre" , esto es lo mismo que rename
describirlo como "rutas cíclicas del sistema de archivos" arriba.
Modifico ligeramente el código y lo hago correr en Kali Linux basado en esta respuesta :
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
void fsize(char *);
void dirwalk(char *, void (*fcn)(char *));
int
main(int argc, char **argv) {
if (argc == 1)
fsize(".");
else
while (--argc > 0) {
printf("start\n");
fsize(*++argv);
}
return 0;
}
void fsize(char *name) {
struct stat stbuf;
if (stat(name, &stbuf) == -1 ) {
fprintf(stderr, "fsize: can't access %s\n", name);
return;
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
dirwalk(name, fsize);
printf("%81d %s\n", stbuf.st_size, name);
}
#define MAX_PATH 1024
void dirwalk(char *dir, void (*fcn)(char *))
{
char name[MAX_PATH];
struct dirent *dp;
DIR *dfd;
if ((dfd = opendir(dir)) == NULL) {
fprintf(stderr, "dirwalk: can't open %s\n", dir);
return;
}
while ((dp = readdir(dfd)) != NULL) {
sleep(1);
printf("d_name: S%sG\n", dp->d_name);
if (strcmp(dp->d_name, ".") == 0
|| strcmp(dp->d_name, "..") == 0) {
printf("hole dot\n");
continue;
}
if (strlen(dir)+strlen(dp->d_name)+2 > sizeof(name)) {
printf("mocha\n");
fprintf(stderr, "dirwalk: name %s/%s too long\n",
dir, dp->d_name);
}
else {
printf("ice\n");
(*fcn)(dp->d_name);
}
}
closedir(dfd);
}
Veamos:
xb@dnxb:/test/dot$ ls -la
total 8
drwxr-xr-x 2 xiaobai xiaobai 4096 Nov 20 04:14 .
drwxr-xr-x 3 xiaobai xiaobai 4096 Nov 20 04:14 ..
xb@dnxb:/test/dot$
xb@dnxb:/test/dot$ cc /tmp/kr/fsize.c -o /tmp/kr/a.out
xb@dnxb:/test/dot$ /tmp/kr/a.out .
start
d_name: S..G
hole dot
d_name: S.G
hole dot
4096 .
xb@dnxb:/test/dot$
Funciona correctamente, ahora qué pasa si comento las continue
instrucciones:
xb@dnxb:/test/dot$ cc /tmp/kr/fsize.c -o /tmp/kr/a.out
xb@dnxb:/test/dot$ /tmp/kr/a.out .
start
d_name: S..G
hole dot
ice
d_name: S..G
hole dot
ice
d_name: S..G
hole dot
ice
^C
xb@dnxb:/test/dot$
Como puede ver, tengo que usar Ctrl+ Cpara eliminar este programa de bucle infinito.
El directorio '..' lee su primera entrada '..' y se repite para siempre.
Conclusión:
GNU findutils
intenta ser compatible con la find
utilidad en * BSD .
find
La utilidad en * BSD utiliza internamente la rmdir
función C compatible con POSIX que no está permitida dot / dot-dot.
La razón de rmdir
no permitir dot / dot-dot es evitar las rutas cíclicas del sistema de archivos.
El lenguaje de programación C escrito por K&R muestra el ejemplo de cómo punto / punto-punto conducirá a un programa de bucle para siempre.
Porque su find
comando regresa .
como resultado. Desde la página de información de rm
:
Cualquier intento de eliminar un archivo cuyo último componente de nombre de archivo es '.' o '..' se rechaza sin ninguna solicitud, como lo ordena POSIX.
Entonces, parece que find
solo se apega a las reglas POSIX en este caso.
/var/log
y lo ejecutaras como root, pensando que eliminaría todos los subdirectorios y también eliminaría el directorio actual?
man
página find
dice: "Si la eliminación falla, se emite un mensaje de error". ¿Por qué no se imprime ningún error?
mkdir foo && cd foo && rmdir $(pwd)
. Está eliminando .
(o ..
) eso no funciona.
La llamada al sistema rmdir falla con EINVAL si el último componente de su ruta de argumento es "."
. Está documentado en http://pubs.opengroup.org/onlinepubs/009695399/functions/rmdir.html
y la justificación del comportamiento es:
El significado de eliminar pathname / dot no está claro, porque el nombre del archivo (directorio) en el directorio principal que se eliminará no está claro, particularmente en presencia de múltiples enlaces a un directorio.
Si bien 林果 皞 y Thomas ya dieron buenas respuestas sobre esto, creo que sus respuestas olvidaron explicar por qué este comportamiento se implementó en primer lugar.
En su find . -delete
ejemplo, eliminar el directorio actual suena bastante lógico y sensato. Pero considere:
$ find . -name marti\*
./martin
./martin.jpg
[..]
¿ .
Todavía te parece lógico y sensato eliminar ?
La eliminación de un directorio no vacío es un error, por lo que es poco probable que pierda datos con esto find
(aunque podría hacerlo rm -r
), pero su shell tendrá su directorio de trabajo actual configurado en un directorio que ya no existe, lo que puede generar confusión. y comportamiento sorprendente:
$ pwd
/home/martin/test
$ rm -r ../test
$ touch foo
touch: cannot touch 'foo': No such file or directory
No eliminar el directorio actual es simplemente un buen diseño de interfaz y cumple con el principio de menor sorpresa.