cp를 사용하여 소프트링크를 하드링크로 변환

cp를 사용하여 소프트링크를 하드링크로 변환

명령 cp페이지 는 다음 info옵션을 제공합니다 .--preserve=

links
해당 소스 파일 간의 모든 링크를 대상 파일에 유지합니다. 참고하세요~와 함께-L' or 이 옵션~할 수 있다심볼릭 링크를 하드 링크로 변환.

그 다음에는 [현재] 이해할 수 없는 예가 나옵니다. 아무리 해도:

질문: 를 사용하여 소프트 링크를 하드 링크로 전환하는 방법은 무엇입니까 cp? 그리고 다시 [하드링크를 소프트링크로 변환]하는 방법이 있나요?


2차 이슈: 어디서요?~할 수 있다위의 인용문이 작동합니까? 나는 -L및 의 목적을 이해하고 -H모든 기능을 갖춘 소프트링크 등을 복사할 수 있지만 지금까지는 소프트링크를 하드링크로 전환하지 못했습니다.

답변1

정보 페이지의 예는 이 예를 따르기가 다소 어렵다는 것을 보여줍니다.

$ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c
74161745 a
74161745 b

이를 구성 요소 명령으로 나누어 보겠습니다.

  • mkdir c;: 디렉토리를 생성합니다c/
  • : > a;: 빈 파일을 만드는 빠른 방법입니다. 와 동일합니다 echo "" > a. :아무것도 하지 않는 bash가 내장되어 있습니다 help :. 를 참조하세요.
  • ln -s a ba: 호출 할 소프트링크를 만듭니다 b. 이 시점에서 현재 디렉터리의 내용은 다음과 같습니다.

    $ ls -l | cc2ter 
    total 4
    -rw-r--r-- 1 terdon terdon    0 Oct  9 02:50 a
    lrwxrwxrwx 1 terdon terdon    1 Oct  9 02:50 b -> a
    drwxr-xr-x 2 terdon terdon 4096 Oct  9 02:50 c
    

    기호 링크(소프트 링크) 는 b다음과 동일한 inode를 가리키지 않습니다 a.

    $ ls -i1c a b
    16647344 a
    16647362 b
    
  • cp -aH a b c;: 파일을 디렉토리에 복사 a합니다 . 여기에서 변환이 발생하며 전달되는 옵션은 다음과 같습니다 .bccp

    -a, --archive
          same as -dR --preserve=all
    -d    same as --no-dereference --preserve=links
    -H    follow command-line symbolic links in SOURCE
    

    -H(에서) 다음과 같은 이유로 필요합니다 info cp.

    심볼릭 링크에서 복사할 때 `cp'는 일반적으로 재귀적으로 복사하지 않을 때만 링크를 따릅니다.

    -a재귀적 복사( -R) 를 활성화 하므로 -H심볼릭 링크를 따라가는 것이 필요합니다. -H재귀에도 불구하고 링크가 따라가며 대상 디렉터리에 하드 링크가 생성된다는 의미입니다. 다음은 마지막 단계 이후의 내용입니다 c/(첫 번째 열은 inode 번호입니다).

    $ ls -li c 
    total 0
    17044704 -rw-r--r-- 2 terdon terdon 0 Oct  9 02:50 a
    17044704 -rw-r--r-- 2 terdon terdon 0 Oct  9 02:50 b
    

이제 그것이 정확히 어떻게 작동하는지에 대해, 내가 그것을 가지고 놀면서 알아낼 수 있는 한, 심볼릭 링크 cp --preserve=links와 결합되거나 다음과 -L같은 -H경우 하드 링크로 변환됩니다.링크와 대상이 모두 복사되고 있습니다.같은예배 규칙서.


사실 OP로서찾아 냈다, 적어도 Debian 시스템에서는 cp --preserve=links대상 디렉토리가 동일한 경우 심볼릭 링크를 하드 링크로 변환하는 데 충분합니다.

답변2

가능한 버그에 대한 보고서를 coreutils 팀 @gnu.org에 문서로 보냈고 info cp다음 답변을 받았습니다.

여기서 문서는 약간 간결합니다. 주요 문제는 -a가 -d를 의미하고 이는 명령이 예상대로 작동하도록 하는 데 필요한 --no-dereference를 의미한다는 것입니다. 소스에서 심볼릭 링크를 암시적으로 따라가는 cp를 중지하려면 IE --no-dereference가 필요합니다.

여기에 설명된 세부 사항을 확인하고 분리하려면 다음을 수행하십시오.

$ mkdir links; : > a; ln -s a b;

여기서 우리는 -d가 뒤에 오는 -H보다 우선한다는 것을 알 수 있습니다. 그러므로 우리는 애초에 심볼릭 링크를 역참조하지 않을 것입니다.

$ rm links/*; cp -H -d a b links
$ l links/
lrwxrwxrwx. 1 padraig 1 Oct 10 09:37 b ▪▶ a
-rw-rw-r--. 1 padraig 0 Oct 10 09:37 a

여기서는 -H가 이제 마지막이므로 적용되므로 소스에서 심볼릭 링크를 따르고 대상에 하드링크가 생성되는 것을 볼 수 있습니다.

$ rm links/*
$ rm links/*; cp -d -H a b links
$ l links
-rw-rw-r--. 2 padraig 0 Oct 10 09:37 b
-rw-rw-r--. 2 padraig 0 Oct 10 09:37 a

다음을 사용하여 문서를 좀 더 명확하게 만들겠습니다.

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index b273627..aeed4ca 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -8257,9 +8257,11 @@ $ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c
 @noindent

입력:은 @file{b}일반 파일에 대한 심볼릭 링크이지만 @file{a}대상 디렉터리의 파일은 @file{c/}하드 링크되어 있습니다.

  • 암시 @option{-a}하고 명령줄 인수를 역참조하라고 지시 @option{--preserve=links}하므로 동일한 inode 번호를 가진 두 개의 파일을 확인하고 인식된 하드 링크를 유지합니다.@option{-H}@command{cp}
  • 이후에는 심볼릭 링크를 복사한다는 @option{-a}의미 이지만 나중에 는 동일한 inode 번호를 가진 두 개의 파일을 볼 수 있는 명령줄 인수를 역참조하도록 지시합니다 . 그런 다음 에도 암시된 옵션은 인식된 하드 링크를 보존합니다.@option{--no-dereference}@option{-H}@command{cp}@option{--preserve=links}@option{-a}

답변3

하드 링크를 심볼릭 링크로 변환하는 것은 어렵습니다. 하드 링크의 경우 파일 시스템에는 이를 가리키는 두 개 이상의 파일 항목이 있는 데이터 블록이 있습니다. "출처"와 "목적지"는 없습니다. 말 그대로 여러 개의 동일한 이름을 가진 하나의 파일입니다. GNU find를 사용하여 다음과 같은 방법으로 이를 식별할 수 있습니다.

sauer@zipper:~$ find . -type f -links +1 -printf "%i: %p (%n)\n"
609: ./link1 (2)
609: ./link2 (2)

동일한 inode를 가진 모든 파일을 얻은 후에는 "실제" 파일이 될 파일 중 하나를 선택한 다음 나머지 파일을 모두 마스터 파일에 대한 심볼릭 링크로 바꿔야 합니다. 아마도 이를 수행하는 방법은 다음을 사용하는 것입니다.

sauer@zipper:~$ find . -type f -links +1 -printf "%i %p\n" | sort -nk1
609 ./link1
609 ./link2

그런 다음 동일한 숫자를 가진 값 중 하나를 선택하여 다른 모든 값을 연결하는 방법을 알아내는 스크립트를 작성하십시오. 아마도 첫 번째 항목이 대상이 되고 동일한 inode를 가진 더 많은 항목이 이에 심볼릭 링크될 수 있습니다. 다음은 정말 간단하고 테스트되지 않은 쉘 스크립트 예입니다.

#!/bin/sh
prev=""
target=""
find /tmp -type f -links +1 -printf "%i %p\n" | sort -nk1 \
| while read inode file
do
  if [[ $inode != $prev ]]
  then
     target="$file"
     prev=$inode
  else
    ln -sf "$target" "$file"
  fi
done

find(이 예에서는 /tmp)의 경로가 절대 경로가 아닌 경우 잘못된 대상을 사용하여 다른 디렉터리의 링크가 생성될 수 있다는 점에서 잠재적인 문제가 있습니다. 그러나 일반적인 아이디어는 괜찮을 것입니다.

관련 정보