なぜ見つかりませんか? -delete現在のディレクトリを削除しますか?

なぜ見つかりませんか? -delete現在のディレクトリを削除しますか?

私は希望

find . -delete

現在のディレクトリは削除されますが、削除されません。なぜできないの?

ベストアンサー1

メンバーはfindutils これに気づく、これは* BSDとの互換性のためです。

「。」アンインストールを省略する理由の1つは、この操作のソースである* BSDとの互換性によるものです。

これ情報findutilsソースコードは、この動作を維持することにしたことを示しています。

#20802: If -delete fails, find's exit status will now be non-zero. However, find still skips trying to delete ".".

【書き直す】

この問題が話題になり、FreeBSDソースコードを掘り下げてより説得力のある理由を見つけました。

私たちに見せてください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);
    }
...

ご覧のとおり、ポイントとポイントをフィルタリングしないと、rmdir()POSIXに到達しますunistd.h

簡単なテストでは、ポイント/ポイントパラメータを持つrmdirは-1を返します。

printf("%d\n", rmdir(".."));

みようPOSIXがrmdirを記述する方法:

path引数が参照するパスの最後のコンポーネントがドットまたはドットポイントの場合、rmdir()は失敗します。

理由は示されていませんshall fail

私が見つけたrename いくつかの理由を説明する数字:

循環ファイルシステムへのパスを回避するには、ドットまたはドットポイントの名前変更を無効にします。

循環ファイルシステムパス

私は見ましたCプログラミング言語(2版)ディレクトリのトピックを検索し、驚くほど発見しました。コードは似ています。:

if(strcmp(dp->name,".") == 0 || strcmp(dp->name,"..") == 0)
    continue;

コメントもあります!

各ディレクトリには常に独自のエントリ(「.」と呼ばれる)と親ディレクトリ「..」が含まれており、それらをスキップする必要があります。それ以外の場合はプログラムが実行されます。永遠に繰り返す

「永遠のループ」、これはrenameそれを説明するのと同じ方法です「循環ファイルシステムパス」以上。

コードを少し変更してKali Linuxベースで動作するようにしました。この回答:

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

みましょう:

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$ 

うまくいきます。今、continueディレクティブをコメントアウトするとどうなりますか?

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$

ご覧のとおり、この無限ループを終了するにはCtrl+を使用する必要があります。C

「..」ディレクトリは最初のエントリ「..」を読み、永久に繰り返されます。

結論として:

  1. GNUはユーティリティfindutilsとの互換性を試みます。find*BSD

  2. find* BSDのユーティリティーは内部的にrmdirPOSIX準拠のC関数を使用し、点/点-点は許可されません。

  3. rmdirdot/dot-dot が許可されない理由は、循環ファイルシステムのパスを防ぐためです。

  4. Cプログラミング言語K&Rによって書かれた例は、ポイント/ポイント-ポイントが永久に繰り返されるプログラムにつながる方法を示しています。

おすすめ記事