rm my-symlink와 rm my-symlink/의 차이점

rm my-symlink와 rm my-symlink/의 차이점

이것을 사용하면 왜 rm -rf my-symlink심볼릭 링크만 제거되고 rm -rf my-symlink/링크된 디렉터리의 파일은 삭제되고 심볼릭 링크는 유지되는지 궁금합니다.

답변1

stat my-symlink와 의 출력을 비교하면 차이점을 확인할 수 있습니다 stat my-symlink/. my-symlink슬래시가 없는 기호 링크 자체는 my-symlink/기호 링크가 가리키는 디렉터리이며, 기호 링크가 my-symlink/가리키는 디렉터리의 inode와 inode를 비교하여 독립적으로 확인할 수 있습니다.

이 정보를 사용하면 표시되는 동작이 에 설명된 것과 일치합니다.rm명세서: 기호 링크를 처리할 때 rm링크가 디렉토리를 가리키는 경우 "아래로" 이동하지 않고 링크를 삭제합니다. 디렉토리를 처리할 때(옵션 사용 -r) 해당 내용을 재귀적으로 삭제합니다. 이 my-symlink/경우 rm"디렉터리"를 삭제하려고 시도하지만 디렉터리가 아니라 심볼릭 링크이기 때문에 실패합니다. 그러나 -f플래그로 인해 오류가 발생하지는 않습니다.

답변2

이 동작을 더 조사해야 한다고 생각했기 때문에 여기에 또 다른 답변이 있습니다.

내부적으로 rmFTS파일 계층 구조로 재귀합니다. fts_open경로 배열을 매개변수로 사용하고 각 경로에 대한 트리 구조를 만듭니다. 이를 통해 프로그래머는 마치 통합 계층의 일부인 것처럼 여러 위치를 원활하게 탐색할 수 있습니다.

FTS를 직접 플레이해볼 수 있는 테스트 프로그램입니다.

#include <stdio.h>
#include <stdlib.h>
#include <fts.h>

int main(int argc, char* argv[])
{
    if(argc < 2) return EXIT_FAILURE;

    char* const* arr = argv + 1;
    FTS* hier = fts_open(arr, FTS_NOSTAT | FTS_PHYSICAL, NULL);

    FTSENT* ent;
    while((ent = fts_read(hier))) {
        printf("%s info=%d (D=%d DP=%d F=%d SL=%d)\n",
               ent->fts_accpath, ent->fts_info,
               ent->fts_info == FTS_D, ent->fts_info == FTS_DP,
               ent->fts_info == FTS_F || ent->fts_info == FTS_NSOK,
               ent->fts_info == FTS_SL);
    }

    fts_close(hier);
    return EXIT_SUCCESS;
}

다음과 같은 디렉터리 구조를 생성했다고 가정합니다.

$ mkdir dir
$ touch dir/file
$ ln -s dir sym

이제 첫 번째 사례를 고려하여 FTS가 탐색을 어떻게 주도하는지 살펴보겠습니다.

$ gcc fts.c 
$ ./a.out sym
sym info=12 (D=0 DP=0 F=0 SL=1)

보시다시피 이 경우에는 sym파일로 처리됩니다. 좀 더 정확하게 말하면 심볼릭 링크입니다. 이 정보를 사용하여 rm파일로 처리하고 을 호출할 수 있습니다 unlinkat(AT_FDCWD, "sym", 0). 마지막 인수(0)는 unlinkat와 유사한 동작을 발생시킵니다 unlink. 즉, 파일을 삭제하는 것뿐입니다. 결과적으로 링크가 사라집니다.

이제 무슨 일이 일어나는지 봅시다 sym/.

$ ./a.out sym/
sym/ info=1 (D=1 DP=0 F=0 SL=0)
file info=11 (D=0 DP=0 F=1 SL=0)
sym/ info=6 (D=0 DP=1 F=0 SL=0)

이 경우 sym대상 디렉터리로 간주됩니다. 먼저 반복 sym한 다음 sym/file다시 반복합니다 sym. 마지막은 FTS 작동 방식 때문입니다. 먼저 내용을 반복한 다음 루트 노드를 반환합니다. 이것은 실제로 당신에게 매우 편리합니다 rm. 첫 번째 패스( D)에서는 파일을 삭제할 수 있고 두 번째 패스( DP)에서는 빈 디렉터리를 삭제합니다.

보시다시피, 이 예에서 FTS는 sym/두 경우 모두 디렉터리로 보고합니다. 이는 경로에 후행 슬래시를 추가하여 커널이 이를 디렉터리로 해석하도록 하기 때문입니다. 링크의 경우 이는 무슨 일이 있어도 링크를 따라간다는 의미입니다.좀 더 기술적인 관점에서 보면 사양에는 다음과 같은 내용이 나와 있습니다.

하나 이상의 슬래시가 아닌 문자를 포함하고 하나 이상의 후행 슬래시로 끝나는 경로 이름은 마치 점 문자( '.' )가 경로 이름에 추가된 것처럼 구문 분석됩니다.

sym/FTS는 디렉터리로 보고하므로 rm마치 빈 디렉터리가 삭제된 것처럼 동작합니다. 따라서 unlinkat(AT_FDCWD, "sym/", AT_REMOVEDIR).unlinkatrmdir

그러나 sym/경로를 확인한 후 unlinkat시스템 호출은 실제로 디렉터리가 제공되지 않았음을 인식합니다. 따라서 ENOTDIR다음을 트리거하는 보고가 발생합니다.

$ rm: cannot remove ‘sym/’: Not a directory

실제로 -f통화에서 해당 플래그를 제거하면... 이것이 바로 표시되는 내용입니다. 자, 이것이 버그인지 기능인지... 모르겠습니다.

관련 정보