중복 파일을 찾아 심볼릭 링크로 대체

중복 파일을 찾아 심볼릭 링크로 대체

주어진 디렉토리에 중복된 파일(이름이 다른 경우에도)이 있는지 확인하고 첫 번째 항목을 가리키는 심볼릭 링크로 바꾸는 방법을 찾으려고 합니다. 시도해봤는데 fdupes중복된 항목만 나열됩니다.
상황은 다음과 같습니다. 아이콘 테마를 원하는 대로 사용자 정의하고 있는데 상위 폴더에서 이름과 위치가 다르고 다른 목적으로 사용되는 아이콘이 많더라도 기본적으로 모두 동일하다는 것을 알게 되었습니다. 그림. 동일한 수정 사항을 20~30번 적용하는 것은 실제로 한 번 필요할 때 중복되므로 이미지 하나만 유지하고 다른 이미지는 모두 심볼릭 링크하고 싶습니다.

예를 들어, fdupes -r ./디렉토리에서 실행 하면 testdir다음 결과가 반환될 수 있습니다.

./file1.png
./file2.png
./subdir1/anotherfile.png
./subdir1/subdir2/yetanotherfile.png

file1.png이 출력이 주어지면 file 만 유지 하고 다른 모든 파일을 삭제한 다음 모든 원본 파일 이름을 유지하면서 해당 파일을 가리키는 심볼릭 링크로 바꾸고 싶습니다 . 따라서 이름은 그대로 유지되지만 복사본이 아닌 file2.png링크가 됩니다 .file1.png

이러한 링크는 절대 경로를 가리켜서는 안 되며, 상위 디렉터리를 가리켜 야 testdir합니다 .yetanotherfile.png../../file1.png/home/testuser/.icons/testdir/file1.png

저는 GUI와 CLI를 모두 포함하는 솔루션에 관심이 있습니다. fdupes제가 알고 있는 도구이기 때문에 반드시 인용할 필요는 없지만 , 다른 도구를 사용하는 솔루션에도 열려 있습니다.

나는 이 모든 것을 처리하는 bash 스크립트를 만드는 것이 그렇게 어렵지 않을 것이라고 확신하지만, 그것을 직접 작성하는 방법을 알아낼 만큼 전문가는 아닙니다.

답변1

너무 많은 스크립트가 마음에 들지 않으면 추천할 수 있습니다.찾다. 지정된 디렉토리에서 중복 파일을 검색하고 이를 하드 또는 심볼릭 링크로 바꿉니다. 저는 이를 사용하여 Ruby gems 디렉터리의 중복을 성공적으로 제거했습니다. 데비안/우분투에서 사용 가능합니다.

답변2

비슷한 상황이 있었지만 제 경우에는 심볼릭 링크가 상대 경로를 가리켜야 하므로 다음과 같이 썼습니다.이 파이썬 스크립트실현시키다:

#!/usr/bin/env python
# Reads fdupes(-r -1) output and create relative symbolic links for each duplicate
# usage: fdupes -r1 . | ./lndupes.py

import os
from os.path import dirname, relpath, basename, join
import sys

lines = sys.stdin.readlines()

for line in lines:
    files = line.strip().split(' ')
    first = files[0]
    print "First: %s "% first
    for dup in files[1:]:
        rel = os.path.relpath(dirname(first), dirname(dup))
        print "Linking duplicate: %s to %s" % (dup, join(rel,basename(first)))
        os.unlink(dup)
        os.symlink(join(rel,basename(first)), dup)

각 입력 줄(파일 목록)에 대해 스크립트는 파일 목록(공백으로 구분)을 분할하고 각 파일에서 첫 번째 파일까지의 상대 경로를 가져온 다음 기호 링크를 만듭니다.

답변3

첫째, 일반적인 하드 링크 대신 심볼릭 링크를 사용해야 하는 이유가 있습니까? 상대 경로가 있는 심볼릭 링크의 필요성을 이해하는 데 어려움을 겪고 있습니다. 이 문제를 해결한 방법은 다음과 같습니다.

나는 fdupes의 데비안(Ubuntu) 버전이 이 -L옵션을 사용하여 중복 링크를 하드 링크로 대체할 수 있다고 생각하지만, 이를 확인하기 위한 데비안 설치가 없습니다.

해당 옵션이 포함된 버전이 없으면 -L제가 찾은 이 작은 bash 스크립트를 사용할 수 있습니다.명령줄 푸.
이 구문은 bash에서만 작동합니다.

fdupes -r -1 path | while read line; do master=""; for file in ${line[*]}; do if [ "x${master}" == "x" ]; then master=$file; else ln -f "${master}" "${file}"; fi; done; done

위 명령은 "path"에서 모든 중복 파일을 찾아 하드 링크로 바꿉니다. 실행 하고 inode 번호를 보면 ls -ilR이를 확인할 수 있습니다. 다음은 10개의 동일한 파일이 포함된 예입니다.

$ ls -ilR

total 20
3094308 -rw------- 1 username group  5 Sep 14 17:21 file
3094311 -rw------- 1 username group  5 Sep 14 17:21 file2
3094312 -rw------- 1 username group  5 Sep 14 17:21 file3
3094313 -rw------- 1 username group  5 Sep 14 17:21 file4
3094314 -rw------- 1 username group  5 Sep 14 17:21 file5
3094315 drwx------ 1 username group 48 Sep 14 17:22 subdirectory

./subdirectory:
total 20
3094316 -rw------- 1 username group 5 Sep 14 17:22 file
3094332 -rw------- 1 username group 5 Sep 14 17:22 file2
3094345 -rw------- 1 username group 5 Sep 14 17:22 file3
3094346 -rw------- 1 username group 5 Sep 14 17:22 file4
3094347 -rw------- 1 username group 5 Sep 14 17:22 file5

모든 파일에는 별도의 inode 번호가 있으므로 별도의 파일이 됩니다. 이제 중복을 제거해 보겠습니다.

$ fdupes -r -1 . | while read line; do j="0"; for file in ${line[*]}; do if [ "$j" == "0" ]; then j="1"; else ln -f ${line// .*/} $file; fi; done; done
$ ls -ilR
.:
total 20
3094308 -rw------- 10 username group  5 Sep 14 17:21 file
3094308 -rw------- 10 username group  5 Sep 14 17:21 file2
3094308 -rw------- 10 username group  5 Sep 14 17:21 file3
3094308 -rw------- 10 username group  5 Sep 14 17:21 file4
3094308 -rw------- 10 username group  5 Sep 14 17:21 file5
3094315 drwx------  1 username group 48 Sep 14 17:24 subdirectory

./subdirectory:
total 20
3094308 -rw------- 10 username group 5 Sep 14 17:21 file
3094308 -rw------- 10 username group 5 Sep 14 17:21 file2
3094308 -rw------- 10 username group 5 Sep 14 17:21 file3
3094308 -rw------- 10 username group 5 Sep 14 17:21 file4
3094308 -rw------- 10 username group 5 Sep 14 17:21 file5

이제 이러한 파일은 모두 동일한 inode 번호를 갖습니다. 이는 모두 디스크의 동일한 물리적 데이터를 가리킨다는 의미입니다.

이것이 귀하의 문제를 해결하거나 최소한 올바른 방향을 제시해주기를 바랍니다.

답변4

몇 가지 참고 사항:

  • BASH 특정
  • 파일 이름에 공백이 없습니다.
  • 각 줄에는 최대 2개의 파일이 포함되어 있다고 가정합니다.

fdupes -1r common/base/dir | while read -r -a line ; do ln -sf $(realpath --relative-to ${line[1]} ${line[0]}) ${line[1]}; done

2개 이상의 파일이 중복된 경우(예: file1, file2, file3) 각 파일 쌍에 대해 심볼릭 링크를 만들어야 합니다. file1, file2 및 file1, file3을 2개의 개별 사례로 생각하세요.

if [[ ${#line[@]} -gt 2 ]] ;then 
  ln -sf $(realpath --relative-to ${line[1]} ${line[0]}) ${line[1]} 
  ln -sf $(realpath --relative-to ${line[2]} ${line[0]}) ${line[2]} 
  ...
fi

행당 중복 항목 수를 자동으로 처리하도록 확장하려면 더 많은 노력이 필요합니다.

또 다른 방법은 먼저 절대 경로를 사용하여 심볼릭 링크를 만든 다음 변환하는 것입니다.

fdupes -1r /absolute/path/common/base/dir | while read -r -a line ; do ln -sf ${line[0]} ${line[1]}; done
chroot /absolute/path/common/base/dir ; symlinks -cr .

이는 @Gilles의 답변을 기반으로 합니다. https://unix.stackexchange.com/a/100955/77319

관련 정보