Je m'attendrais
find . -delete
pour supprimer le répertoire courant, mais ce n'est pas le cas. Pourquoi pas?
find . -print
.
cd ..; rm -r dir
avec un autre shell avec une sémantique assez claire ...
Je m'attendrais
find . -delete
pour supprimer le répertoire courant, mais ce n'est pas le cas. Pourquoi pas?
find . -print
.
cd ..; rm -r dir
avec un autre shell avec une sémantique assez claire ...
Réponses:
Les membres en sont findutils
conscients , c'est pour compatible avec * BSD:
L'une des raisons pour lesquelles nous ignorons la suppression de "." est pour la compatibilité avec * BSD, où cette action a commencé.
Les NOUVELLES du code source de findutils montrent qu'ils ont décidé de conserver le comportement:
#20802: If -delete fails, find's exit status will now be non-zero. However, find still skips trying to delete ".".
[MISE À JOUR]
Étant donné que cette question est devenue l'un des sujets d'actualité, je plonge dans le code source de FreeBSD et j'en viens à une raison plus convaincante.
Voyons le code source de l'utilitaire de recherche 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);
}
...
Comme vous pouvez le voir, s'il ne filtre pas les points et les points, il atteindra la rmdir()
fonction C définie par POSIX unistd.h
.
Faites un test simple, rmdir avec l'argument point / point-point retournera -1:
printf("%d\n", rmdir(".."));
Voyons comment POSIX décrit rmdir :
Si l'argument path fait référence à un chemin dont la dernière composante est soit dot soit dot-dot, rmdir () échouera.
Aucune raison n'a été donnée pourquoi shall fail
.
J'ai trouvé rename
expliquer quelque raison n:
Renommer un point ou un point-point est interdit afin d'empêcher les chemins cycliques du système de fichiers.
Chemins cycliques du système de fichiers ?
Je regarde le langage de programmation C (2e édition) et recherche un sujet de répertoire, étonnamment j'ai trouvé que le code est similaire :
if(strcmp(dp->name,".") == 0 || strcmp(dp->name,"..") == 0)
continue;
Et le commentaire!
Chaque répertoire contient toujours des entrées pour lui-même, appelées ".", Et son parent, ".."; ceux-ci doivent être ignorés, sinon le programme sera en boucle pour toujours .
"boucle pour toujours" , c'est la même chose que la façon de le rename
décrire comme "chemins de système de fichiers cycliques" ci-dessus.
Je modifie légèrement le code et pour le faire fonctionner sous Kali Linux basé sur cette réponse :
#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);
}
Voyons voir:
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$
Cela fonctionne correctement, maintenant que se passe-t-il si je commente l' continue
instruction:
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$
Comme vous pouvez le voir, je dois utiliser Ctrl+ Cpour tuer ce programme en boucle infinie.
Le répertoire '..' lit sa première entrée '..' et boucle pour toujours.
Conclusion:
GNU findutils
essaie d'être compatible avec l' find
utilitaire dans * BSD .
find
l'utilitaire dans * BSD utilise en interne la rmdir
fonction C conforme POSIX que le point / point-point n'est pas autorisé.
La raison de l' rmdir
interdiction de point / point-point est d'empêcher les chemins cycliques du système de fichiers.
Le langage de programmation C écrit par K&R montre l'exemple de la façon dont point / point-point mènera au programme de boucle pour toujours.
Parce que votre find
commande retourne .
comme résultat. Depuis la page info de rm
:
Toute tentative de suppression d'un fichier dont le dernier composant du nom de fichier est '.' ou '..' est rejeté sans aucune invite, comme mandaté par POSIX.
Ainsi, il semble que find
les règles POSIX restent dans ce cas.
/var/log
et que vous l'avez exécuté en tant que root, pensant qu'il supprimerait tous les sous-répertoires et qu'il supprimait également le répertoire actuel?
man
page pour find
dit: "Si la suppression a échoué, un message d'erreur est émis." Pourquoi aucune erreur n'est-elle imprimée?
mkdir foo && cd foo && rmdir $(pwd)
. C'est la suppression .
(ou ..
) qui ne fonctionne pas.
L'appel système rmdir échoue avec EINVAL si le dernier composant de son chemin d'argument est "."
. Il est documenté à http://pubs.opengroup.org/onlinepubs/009695399/functions/rmdir.html
et la justification de ce comportement est:
La signification de la suppression du nom de chemin / point n'est pas claire, car le nom du fichier (répertoire) dans le répertoire parent à supprimer n'est pas clair, en particulier en présence de plusieurs liens vers un répertoire.
Alors que 林果 皞 et Thomas ont déjà donné de bonnes réponses à ce sujet, je pense que leurs réponses ont oublié d'expliquer pourquoi ce comportement a été mis en œuvre en premier lieu.
Dans votre find . -delete
exemple, la suppression du répertoire actuel semble assez logique et sensée. Mais considérez:
$ find . -name marti\*
./martin
./martin.jpg
[..]
Supprime .
semble- toujours logique et sensée?
La suppression d'un répertoire non vide est une erreur - il est donc peu probable que vous perdiez des données avec cela avec find
(bien que vous puissiez le faire avec rm -r
) - mais votre shell aura son répertoire de travail actuel défini dans un répertoire qui n'existe plus, ce qui peut prêter à confusion et un comportement surprenant:
$ pwd
/home/martin/test
$ rm -r ../test
$ touch foo
touch: cannot touch 'foo': No such file or directory
Ne pas supprimer le répertoire actuel est tout simplement une bonne conception d'interface et est conforme au principe de la moindre surprise.