私は希望
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(".."));
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
「..」ディレクトリは最初のエントリ「..」を読み、永久に繰り返されます。
結論として:
GNUはユーティリティ
findutils
との互換性を試みます。find
*BSD。find
* BSDのユーティリティーは内部的にrmdir
POSIX準拠のC関数を使用し、点/点-点は許可されません。rmdir
dot/dot-dot が許可されない理由は、循環ファイルシステムのパスを防ぐためです。Cプログラミング言語K&Rによって書かれた例は、ポイント/ポイント-ポイントが永久に繰り返されるプログラムにつながる方法を示しています。
答え2
find
コマンドが結果を返すからです.
。情報ページからrm
:
最後のファイル名部分が '.'または、「..」のファイルを削除しようとすると、POSIXで指定されているようにプロンプトなしで拒否されます。
find
したがって、この場合はPOSIXの規則に従うようです。
答え3
"."
rmdir システムコールの引数パスの最後のコンポーネントがある場合、rmdir システムコールは失敗し、EINVAL を返します。に記録されています。http://pubs.opengroup.org/onlinepubs/009695399/functions/rmdir.html
この措置の根拠は次のとおりです。
パス名/ dot削除の意味は、削除される親ディレクトリのファイル(ディレクトリ)名が不明であるため不明です。特にディレクトリリンクが複数ある場合にはさらにそうです。
答え4
Lin GuohaoとThomasがこれについて良い答えをしましたが、彼らの答えは説明を忘れてしまったようです。なぜこの行為が最初に行われた。
あなたの例からfind . -delete
現在のディレクトリを削除すると、非常に論理的で健全なように聞こえます。ただし、次の点を考慮してください。
$ find . -name marti\*
./martin
./martin.jpg
[..]
削除は.
まだ論理的で健全に聞こえますか?
空でないディレクトリを削除するのは間違いです。したがって、データを失う可能性はありませんfind
(もちろんそうかもしれませんがrm -r
)。しかし、シェルは現在の作業ディレクトリをもはや存在しないディレクトリに設定し、混乱し、驚くべき動作を引き起こします。
$ pwd
/home/martin/test
$ rm -r ../test
$ touch foo
touch: cannot touch 'foo': No such file or directory
いいえ現在のディレクトリを削除することは、最小限の驚きの原則に準拠する優れたインターフェイスデザインです。