it-swarm-ko.com

실제 하드 링크를 사용 하시겠습니까?

난 달린다

ln /a/A /b/B

파일 a에 의해 가리키는 폴더 ls에서보고 싶습니다.

파일의 inode 번호를 찾을 수 있습니다.

ls -i

ls -l

참조 횟수 (특정 inode에 대한 하드 링크 수)

inode 번호를 찾으면 동일한 inode를 가진 모든 파일을 검색 할 수 있습니다.

find . -inum NUM

현재 디렉토리 (.)에 inode NUM의 파일 이름을 표시합니다.

163
zzr

귀하의 질문에 대한 명확한 답변은 없습니다. 심볼릭 링크와 달리 하드 링크는 "원래 파일"과 구별 할 수 없습니다.

디렉토리 항목은 파일 이름과 inode에 대한 포인터로 구성됩니다. inode는 차례대로 파일 메타 데이터와 실제 파일 내용 (포인터)을 포함합니다. 하드 링크를 만들면 동일한 inode에 대한 다른 파일 이름 + 참조가 만들어집니다. 이러한 참조는 단방향 (일반적인 파일 시스템에서 최소한)입니다. 즉, inode는 참조 카운트 만 유지합니다. "원본"파일 이름이 무엇인지 알아내는 본질적인 방법은 없습니다.

그런데이 때문에 파일을 "삭제"하는 시스템 호출을 unlink이라고합니다. 하드 링크 만 제거하면됩니다. 아이 노드의 참조 횟수가 0으로 떨어지면 첨부 된 데이터가 삭제됩니다.

주어진 inode에 대한 다른 참조를 찾는 유일한 방법은 파일 시스템을 철저히 검색하여 어떤 파일이 해당 inode를 참조하는지 확인하는 것입니다. 셸에서 'test A -ef B'를 사용하여이 검사를 수행 할 수 있습니다.

60
Laurence Gonsalves

UNIX에는 하드 링크와 심볼 링크 (각각 "ln""ln -s"로 작성)가 있습니다. 심볼릭 링크는 단순히 다른 파일에 대한 실제 경로를 포함하고 파일 시스템을 교차 할 수있는 파일입니다.

하드 링크는 유닉스 초기부터 사용되어 왔습니다. (어쨌든 기억할 수 있습니다. 그것들은 동일한 기본 데이터 정확한 을 참조하는 두 개의 디렉토리 항목입니다. 파일의 데이터는 inode에 의해 지정됩니다. 파일 시스템의 각 파일은 inode를 가리 킵니다.하지만 각 파일이 고유 한 inode를 가리킬 필요는 없습니다. 즉, 하드 링크의 출처입니다.

Inode는 주어진 파일 시스템에 대해서만 유일하기 때문에, 하드 링크는 (심볼릭 링크와 달리) 같은 파일 시스템에 있어야한다는 제한이 있습니다. 심볼릭 링크와 달리 권한이 부여 된 파일은 없습니다. 모두 동일합니다. 데이터 영역은 모두 해당 inode를 사용하는 파일이 삭제 될 때만 (그리고 모든 프로세스가 그것을 닫습니다.하지만 다른 문제입니다).

"ls -i" 명령을 사용하여 특정 파일의 inode를 가져올 수 있습니다. 그런 다음 "find <filesystemroot> -inum <inode>" 명령을 사용하여 주어진 inode를 가진 파일 시스템의 모든 파일을 찾을 수 있습니다.

다음은 정확히 수행하는 스크립트입니다. 당신은 그것을 다음과 같이 호출합니다 :

findhardlinks ~/jquery.js

그리고 그 파일에 대한 하드 링크 인 해당 파일 시스템의 모든 파일을 찾습니다 :

[email protected]:~# ./findhardlinks /home/pax/jquery.js
Processing '/home/pax/jquery.js'
   '/home/pax/jquery.js' has inode 5211995 on mount point '/'
       /home/common/jquery-1.2.6.min.js
       /home/pax/jquery.js

여기 스크립트가 있습니다.

#!/bin/bash
if [[ $# -lt 1 ]] ; then
    echo "Usage: findhardlinks <fileOrDirToFindFor> ..."
    exit 1
fi

while [[ $# -ge 1 ]] ; do
    echo "Processing '$1'"
    if [[ ! -r "$1" ]] ; then
        echo "   '$1' is not accessible"
    else
        numlinks=$(ls -ld "$1" | awk '{print $2}')
        inode=$(ls -id "$1" | awk '{print $1}' | head -1l)
        device=$(df "$1" | tail -1l | awk '{print $6}')
        echo "   '$1' has inode ${inode} on mount point '${device}'"
        find ${device} -inum ${inode} 2>/dev/null | sed 's/^/        /'
    fi
    shift
done
33
user53528
ls -l

첫 번째 열은 사용 권한을 나타냅니다. 두 번째 열은 하위 항목 수 (디렉토리의 경우) 또는 동일한 데이터 (원본 파일을 포함한 하드 링크의 경우)까지의 파일 수입니다. 예 :

[email protected]    2    [username]    [group]    [timestamp]     HardLink
[email protected]    2    [username]    [group]    [timestamp]     Original
               ^ Number of hard links to the data
24
eyelidlessness

다음 단순한 어때? (Latter는 위의 긴 스크립트를 대체 할 수 있습니다!)

<THEFILENAME>라는 특정 파일이 있고 <TARGETDIR> 디렉토리 (모든 파일 시스템이 /로 표시 될 수도 있음)를 통해 확산되는 모든 하드 링크를 알고 싶다면,

find <TARGETDIR> -type f -samefile  <THEFILENAME>

논리를 확장하여 <SOURCEDIR>에있는 여러 개의 하드 링크가있는 <TARGETDIR>의 모든 파일을 알고 싶다면 다음을 수행하십시오.

find <SOURCEDIR> -type f -links +1   \
  -printf "\n\n %n HardLinks of file : %H/%f  \n"   \
  -exec find <TARGETDIR> -type f -samefile {} \; 
11
Loves Probability

파일 시스템에서 모든 하드 링크를 찾는 스크립트에 대한 많은 답이 있습니다. 그들 대부분은 여러개의 링크 된 파일에 대해 -samefile를 찾기 위해 전체 파일 시스템을 검색하는 것과 같은 바보 같은 일을합니다. 이것은 미친 짓이다. inode 번호를 정렬하고 중복 된 것을 인쇄하기 만하면됩니다.

find directories.. -xdev ! -type d -links +1 -printf '%20D %20i %p\n' | sort -n | uniq -w 42 --all-repeated=separate (FS-id (%D)를 지원하고 정규 파일이 아닌 모든 비 디렉토리 파일 유형을 처리하는 본래의 명령을 조정할 수있는 @Tino 덕분에 다중 링크 된 심볼릭 링크, 파이프 등을 찾을 수 있습니다)

! -type d -links +1를 사용하면 정렬의 입력이 uniq의 최종 출력만큼 ​​커야 함을 의미합니다. 하드 링크 집합 중 하나만 포함하는 하위 디렉토리에서 실행하지 않는 한. 어쨌든,이 방법은 다른 게시 된 솔루션보다 파일 시스템을 다시 가로 지르는 CPU 시간을 적게 사용합니다.

샘플 출력 :

...
            2429             76732484 /home/peter/weird-filenames/test/.hiddendir/foo bar
            2429             76732484 /home/peter/weird-filenames/test.orig/.hiddendir/foo bar

            2430             17961006 /usr/bin/pkg-config.real
            2430             17961006 /usr/bin/x86_64-pc-linux-gnu-pkg-config

            2430             36646920 /usr/lib/i386-linux-gnu/dri/i915_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/i965_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/nouveau_vieux_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/r200_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/radeon_dri.so
...

TODO ?: 출력을 un-pad. uniq에는 필드 선택 지원이 매우 제한되어 있으므로 find 출력을 채우고 고정 너비를 사용합니다. 20chars는 가능한 최대 inode 또는 장치 번호 (2 ^ 64-1 = 18446744073709551615)에 대해 충분히 넓습니다. XFS는 0에서 연속적으로가 아니라 디스크가 할당 된 위치를 기반으로 inode 번호를 선택하므로 수십억 개의 파일이 없더라도 큰 XFS 파일 시스템은 32 비트 이상의 inode 번호를 가질 수 있습니다. 다른 파일 시스템은 거대하지 않더라도 20 자리 아이 노드 번호를 가질 수 있습니다.

TODO : 중복 된 그룹을 경로별로 정렬합니다. 마운트 지점별로 정렬 한 다음, 많은 하드 링크가있는 몇 개의 하위 디렉토리가있는 경우에는 inode 번호가 함께 섞입니다. (즉, dup-groups 그룹은 합쳐 지지만 결과는 그들을 혼합합니다).

마지막 sort -k 3는 줄을 개별적으로 정렬하며 줄의 그룹은 단일 레코드로 정렬하지 않습니다. 한 쌍의 개행을 NUL 바이트로 변환하고 GNU sort --zero-terminated -k 3를 사용하여 전처리하면 트릭을 할 수 있습니다. tr은 2-> 1 또는 1-> 2 패턴이 아닌 단일 문자로만 작동합니다. Perl (또는 Perl 또는 awk 내에서 구문 분석 및 정렬)을 수행합니다. sed도 사용할 수 있습니다.

4
Peter Cordes

이것은 Torocoro-Macho의 독자적인 답과 스크립트에 다소 댓글이 달렸지 만 댓글 상자에는 맞지 않습니다 .


정보를 찾는 더 간단한 방법으로 스크립트를 작성하여 프로세스 호출을 줄였습니다.

#!/bin/sh
xPATH=$(readlink -f -- "${1}")
for xFILE in "${xPATH}"/*; do
    [ -d "${xFILE}" ] && continue
    [ ! -r "${xFILE}" ] && printf '"%s" is not readable.\n' "${xFILE}" 1>&2 && continue
    nLINKS=$(stat -c%h "${xFILE}")
    if [ ${nLINKS} -gt 1 ]; then
        iNODE=$(stat -c%i "${xFILE}")
        xDEVICE=$(stat -c%m "${xFILE}")
        printf '\nItem: %s[%d] = %s\n' "${xDEVICE}" "${iNODE}" "${xFILE}";
        find "${xDEVICE}" -inum ${iNODE} -not -path "${xFILE}" -printf '     -> %p\n' 2>/dev/null
    fi
done

쉽게 비교할 수 있도록 가능한 한 당신과 비슷한 것으로 유지하려고했습니다.

이 스크립트 및 귀하의 의견

  • Glob가 불필요하게 복잡하고 파일 이름에 실제로 개행을 포함 할 수 있기 때문에 항상 $IFS 마법을 피해야합니다 (실제로는 대부분 첫 번째 이유입니다).

  • 조만간 당신을 물릴 것이기 때문에 ls과 그 출력을 가능한 한 많이 구문 분석하는 것을 피해야합니다. 예 : 첫 번째 awk 줄에 공백이 포함 된 모든 파일 이름에 실패합니다.

  • printf%s 문법으로 매우 견고하기 때문에 종종 문제를 저장합니다. 또한 출력을 완벽하게 제어 할 수 있으며 echo과는 달리 all시스템에서 일관됩니다.

  • stat은이 경우 많은 논리를 저장할 수 있습니다.

  • GNU find는 강력합니다.

  • headtail 호출은 예를 들어 다음과 같이 awk에서 직접 처리 될 수 있습니다. exit 명령을 사용하거나 NR 변수를 선택하십시오. 이렇게하면 프로세스 호출을 줄일 수 있습니다. 프로세스 호출은 성능이 심각한 스크립트에서 성능을 심각하게 향상시킵니다.

  • egrepgrep 일 수 있습니다.

3
Daniel Andersson

findhardlinks 스크립트 (hard-links로 이름이 바뀜)를 기반으로, 이것이 내가 리팩터링하여 작동하게 한 것입니다.

산출:

# ./hard-links /root

Item: /[10145] = /root/.profile
    -> /proc/907/sched
    -> /<some-where>/.profile

Item: /[10144] = /root/.tested
    -> /proc/907/limits
    -> /<some-where else>/.bashrc
    -> /root/.testlnk

Item: /[10144] = /root/.testlnk
    -> /proc/907/limits
    -> /<another-place else>/.bashrc
    -> /root/.tested

# cat ./hard-links
#!/bin/bash
oIFS="${IFS}"; IFS=$'\n';
xPATH="${1}";
xFILES="`ls -al ${xPATH}|egrep "^-"|awk '{print $9}'`";
for xFILE in ${xFILES[@]}; do
  xITEM="${xPATH}/${xFILE}";
  if [[ ! -r "${xITEM}" ]] ; then
    echo "Path: '${xITEM}' is not accessible! ";
  else
    nLINKS=$(ls -ld "${xITEM}" | awk '{print $2}')
    if [ ${nLINKS} -gt 1 ]; then
      iNODE=$(ls -id "${xITEM}" | awk '{print $1}' | head -1l)
      xDEVICE=$(df "${xITEM}" | tail -1l | awk '{print $6}')
      echo -e "\nItem: ${xDEVICE}[$iNODE] = ${xITEM}";
      find ${xDEVICE} -inum ${iNODE} 2>/dev/null|egrep -v "${xITEM}"|sed 's/^/   -> /';
    fi
  fi
done
IFS="${oIFS}"; echo "";
2
Torocoro-Macho

GUI 솔루션은 여러분의 질문에 정말 가깝습니다.

이전의 주석가들이 지적했듯이 "names"파일은 동일한 데이터에 대한 단순한 별명이기 때문에 "ls"에서 실제 하드 링크 된 파일을 나열 할 수 없습니다. 그러나 실제로 리눅스에서 동일한 데이터 (하드 링크와 같은)를 가리키는 파일 이름의 경로 목록을 표시하는 GUI 도구가 있습니다.이 도구는 FSLint라고합니다. 원하는 옵션은 "이름 충돌"아래에 있습니다 -> 검색 (XX) -> "checkbox $ PATH"의 선택을 해제하고 상단 중간에 "~ ..."뒤에 드롭 다운 상자에서 "별칭"을 선택하십시오.

FSLint는 문서화가 잘되어 있지 않지만, "Recurse"를 위해 체크 박스가 선택된 "Search path"아래의 제한된 디렉토리 트리를 만드는 것이 발견되었습니다. 앞에서 설명한 옵션을 사용하면 프로그램 검색 후 동일한 데이터를 가리키는 경로와 이름을 가진 하드 링크 된 데이터 목록이 생성됩니다.

1
Charles

'alias'를 사용하여 하드 링크를 강조 표시하도록 ls을 구성 할 수 있지만 앞에서 언급했듯이 하드 링크의 '소스'를 표시 할 방법이 없으므로 .hardlink를 추가하면 도움이됩니다.

highlight hardlinks

.bashrc에 다음을 추가하십시오.

alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
1
Daniel Sokolowski