나는 기대할 것이다
find . -delete
현재 디렉토리를 삭제하지만 삭제하지는 않습니다. 왜 안돼?
find . -print.
cd ..; rm -r dir의미가 명확한 다른 쉘을 사용할 수 있습니다 .
나는 기대할 것이다
find . -delete
현재 디렉토리를 삭제하지만 삭제하지는 않습니다. 왜 안돼?
find . -print.
cd ..; rm -r dir의미가 명확한 다른 쉘을 사용할 수 있습니다 .
답변:
findutils 그것을 알고 있는 멤버는 * BSD와 호환됩니다.
"."삭제를 건너 뛰는 이유 중 하나입니다. 이 동작이 시작된 * BSD와의 호환성을위한 것입니다.
findutils 소스 코드 의 NEWS 는 동작을 유지하기로 결정했음을 보여줍니다.
#20802: If -delete fails, find's exit status will now be non-zero. However, find still skips trying to delete ".".
[최신 정보]
이 질문은 뜨거운 주제 중 하나가되었으므로 FreeBSD 소스 코드를 살펴보고 더 설득력있는 이유를 제시합니다.
FreeBSD 의 find 유틸리티 소스 코드를 보자 :
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 's에 의해 정의 된 C 함수에 도달 unistd.h합니다.
간단한 테스트를 수행하십시오 .dot / dot-dot 인수가있는 rmdir은 -1을 반환합니다.
printf("%d\n", rmdir(".."));
POSIX가 rmdir을 어떻게 설명하는지 살펴 보자 .
path 인수가 최종 구성 요소가 dot 또는 dot-dot 인 경로를 참조하면 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 는 * BSD의 유틸리티 findutils와 호환을 시도합니다 .find
find* BSD의 유틸리티는 내부적 rmdir으로 dot / dot-dot가 허용되지 않는 POSIX 호환 C 함수를 사용합니다.
rmdir도트 / 도트를 허용하지 않는 이유는 주기적 파일 시스템 경로를 방지하기위한 것입니다.
K & R이 작성한 C 프로그래밍 언어 는 도트 / 도트가 어떻게 영원히 루프 프로그램을 만드는지를 보여줍니다.
당신 때문에 find명령이 리턴 .결과. 의 정보 페이지에서 rm:
마지막 파일 이름 구성 요소가 '.'인 파일을 제거하려고 시도했습니다. 또는 POSIX에서 지시 한대로 프롬프트없이 '..'이 거부됩니다.
따라서이 find경우 POSIX 규칙을 고수 하는 것처럼 보입니다 .
/var/log있고 루트로 실행하면 모든 하위 디렉토리가 제거되고 현재 디렉토리도 제거되었다고 생각하면 어떻게됩니까?
man페이지는 find말한다 : "제거 오류 메시지가 발행되고, 실패하면." 왜 오류가 인쇄되지 않습니까?
mkdir foo && cd foo && rmdir $(pwd). 작동하지 않는 .(또는 ..) 제거 중 입니다.
인수 경로의 마지막 구성 요소가 인 경우 rmdir 시스템 호출은 EINVAL과 함께 실패합니다 ".". http://pubs.opengroup.org/onlinepubs/009695399/functions/rmdir.html에 문서화되어
있으며 동작의 근거는 다음과 같습니다.
제거 할 상위 디렉토리의 파일 (디렉토리) 이름, 특히 디렉토리에 대한 여러 개의 링크가있는 경우 경로 이름 / dot를 삭제하는 의미는 명확하지 않습니다.
林果 皞와 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
현재 디렉토리를 삭제 하지 않는 것은 단순히 훌륭한 인터페이스 디자인이며 최소한의 놀람 원칙을 준수합니다.