파일이 이미 양쪽에 있을 때 디렉터리 구조를 동기화할 수 있는 방법이 있습니까?

파일이 이미 양쪽에 있을 때 디렉터리 구조를 동기화할 수 있는 방법이 있습니까?

파일은 동일하지만 디렉터리 구조가 완전히 다른 두 개의 드라이브가 있습니다.

소스 측의 구조와 일치하도록 대상 측의 모든 파일을 "이동"하는 방법이 있습니까? 어쩌면 스크립트가 있을까요?

예를 들어, 드라이브 A에는 다음이 있습니다.

/foo/bar/123.txt
/foo/bar/234.txt
/foo/bar/dir/567.txt

B 드라이브에는 다음이 있습니다.

/some/other/path/123.txt
/bar/doo2/wow/234.txt
/bar/doo/567.txt

문제의 파일은 대용량(800GB)이므로 다시 복사하고 싶지 않고 필요한 디렉터리를 만들고 파일을 이동하여 구조를 동기화하고 싶습니다.

나는 대상의 모든 소스 파일을 찾은 다음 이를 일치하는 디렉터리로 이동하고 필요한 경우 생성하는 재귀 스크립트를 생각하고 있습니다. 하지만-이건 내 능력 밖의 일이야!

또 다른 우아한 솔루션이 여기에 제공됩니다. https://superuser.com/questions/237387/any-way-to-sync-directory-struct-when-the-files-are-already-on-both-sides/238086

답변1

Gilles와 함께 가서 제안대로 Unison을 알려드리겠습니다.하산제. Unison은 DropBox보다 20년 앞선 DropBox입니다. 많은 사람들(나 자신 포함)이 매일 사용하는 견고한 코드 - 배울 가치가 충분히 있습니다. 여전히 join얻을 수 있는 모든 홍보가 필요합니다 :)


이것은 답의 절반에 불과하지만 다시 일하러 가야 합니다 :)

기본적으로 저는 정확히 이를 수행하는 잘 알려지지 않은 join유틸리티를 보여주고 싶습니다. 즉, 특정 필드에서 두 테이블을 조인하는 것입니다.

먼저 공백이 포함된 파일 이름을 포함하는 테스트 사례를 설정합니다.

for d in a b 'c c'; do mkdir -p "old/$d"; echo $RANDOM > "old/${d}/${d}.txt"; done
cp -r old new

(일부 디렉토리 및/또는 파일 이름 편집 new)

이제 우리는 각 디렉터리(해시 -> 파일 이름)에 대한 맵을 구축한 다음 이를 사용하여 join동일한 해시와 파일을 일치시키려고 합니다. 지도를 생성하려면 다음을 입력하세요 makemap.sh.

find "$1" -type f -exec md5 -r "{}" \; \
  | sed "s/\([a-z0-9]*\) ${1}\/\(.*\)/\1 \"\2\"/" \

makemap.sh"hash "filename"" 형식의 행이 포함된 파일을 생성하므로 첫 번째 열만 결합합니다.

join <(./makemap.sh 'old') <(./makemap.sh 'new') >moves.txt

그러면 moves.txt다음과 같은 결과가 생성됩니다.

49787681dd7fcc685372784915855431 "a/a.txt" "bar/a.txt"
bfdaa3e91029d31610739d552ede0c26 "c c/c c.txt" "c c/c c.txt"

다음 단계는 실제로 작업을 수행하는 것이지만 내 시도가 참조에 갇히게 되어 도움 mv -imkdir -p될 것입니다.

답변2

unison이라는 유틸리티가 있습니다.

http://www.cis.upenn.edu/~bcpierce/unison/

웹사이트 설명:

Unison은 Unix와 Windows용 파일 동기화 도구입니다. 이를 통해 파일 및 디렉터리 모음의 두 복사본을 다른 호스트(또는 동일한 호스트의 다른 디스크)에 저장하고 별도로 수정한 다음 각 복사본의 변경 사항을 다른 복사본에 전파하여 업데이트할 수 있습니다.

ssh://localhost/path/to/dirUnison은 루트 중 하나 이상이 원격인 경우 첫 번째 실행 시 이동된 파일만 감지하므로 로컬 파일을 동기화하는 경우에도 루트 중 하나로 사용할 수 있습니다 .

답변3

한마음으로 사용~처럼hasen j가 제안한 것. 이 답변은 유용할 수 있는 스크립트의 예로 또는 기본 유틸리티만 설치된 서버에 남겨 둡니다.


파일 이름은 계층 전체에서 고유하다고 가정합니다. 또한 파일 이름에는 개행 문자가 포함되어 있지 않으며 디렉토리 트리에는 디렉토리와 일반 파일만 포함되어 있다고 가정합니다.

  1. 먼저 소스의 파일명을 수집합니다.

    (cd /A && find . \! -type d) >A.find
    
  2. 그런 다음 파일을 대상 쪽의 적절한 위치로 이동합니다. 먼저 대상에 평면화된 파일 트리를 만듭니다. 이전 계층 구조에 하드 링크를 유지하려면 ln대신 사용하세요.mv

    mkdir /B.staging /B.new
    find /B.old -type f -exec sh -c 'mv -- "$@" "$0"' /B.staging {} +
    
  3. 일부 파일이 대상에서 누락될 수 있는 경우 유사한 플랫 파일을 만들고 /A.stagingrsync를 사용하여 소스에서 대상으로 데이터를 복사합니다.

    rsync -au /A.staging/ /B.staging/
    
  4. 이제 파일 이름을 바꾸십시오.

    cd /B.new &&
    <A.find perl -l -ne '
      my $dir = '.'; s!^\./+!!;
      while (s!^([^/]+)/+!!) {  # Create directories as needed
        $dir .= "/$1";
        -d $dir or mkdir $dir or die "mkdir $dir: $!"
      }
      rename "/B.staging/$_", "$dir/$_" or die "rename -> $dir/$_: $!"
    '
    

    동등하게:

    cd /B.new &&
    <A.find python -c '
    import os, sys
    for path in sys.stdin.read().splitlines():
        dir, base = path.rsplit("/", 2)
        os.rename(os.path.join("/B.new", base), path)
    '
    
  5. 마지막으로 디렉터리의 메타데이터에 관심이 있다면 이미 있는 파일을 사용하여 rsync를 호출하세요.

    rsync -au /A/ /B.new/
    

이 기사의 스니펫은 테스트하지 않았습니다. 자신의 책임하에 사용하십시오. 댓글로 버그를 신고해주세요.

답변4

특히 지속적인 동기화가 유용한 경우, 알아내려고 노력할 수 있습니다.자식 첨부.

비교적 새롭습니다. 아직 직접 사용해 본 적이 없습니다.

내가 제안할 수 있는 이유는 파일의 두 번째 복사본을 유지하지 않기 때문입니다. 이는 Git이 아닌 일부 버전 제어 시스템처럼 파일을 읽기 전용("잠김")으로 표시해야 함을 의미합니다.

파일은 sha256sum + 파일 확장자(기본값)로 식별됩니다. 따라서 쓰기를 수행하지 않고(필요한 경우 낮은 대역폭 네트워크를 통해) 파일 내용은 동일하지만 파일 이름이 다른 두 저장소를 동기화할 수 있어야 합니다. 물론 체크섬을 수행하려면 모든 파일을 읽어야 합니다.

관련 정보