재귀적 이동(`mv -rn`, 예: `cp -rn`), 존재하지 않는 파일만 이동

재귀적 이동(`mv -rn`, 예: `cp -rn`), 존재하지 않는 파일만 이동

문맥

백업해야 하는 사용자 업로드 콘텐츠가 있습니다. 콘텐츠는 3개의 별도 서버 /var/www/domain/media/(각 서버에 함께 위치)에서 호스팅됩니다. 백업은 NFS RAID에 마운트됩니다 /var/www/domain/bak/.

media/다른 사용자에 속하는 것과 달리 bak/기본적으로 웹 애플리케이션은 쓰기는 가능 media/하지만 읽기만 bak/가능합니다. 사용자는 업로드한 내용이 GMT 00:00에 백업될 때까지만 삭제할 수 있습니다.

이로 인해 두 가지 문제가 발생합니다. 사용자가 동일한 파일 이름으로 백업의 파일을 강제로 덮어쓸 수 있으며 파일이 media/두 개의 다른 서버에 있을 수 있습니다(사용자가 다른 서버에서 두 번 업로드하는 경우).

모두 4x CenOS 7(Web X 3 + Backup X 1)에서 실행됩니다. "웹" 서버는 디스크 공간이 제한되어 있으므로 디스크가 가득 차는 것을 방지하려면 콘텐츠를 백업 서버로 이동해야 합니다.

가지다경쟁 조건 없음그러므로 이것은 우리가 걱정할 필요가 없는 것입니다. 백업은 ssh다른 세 머신에서 순차적으로 명령을 실행하여 단일 백업 머신에서 수행됩니다.


현재 솔루션

백업할 파일의 "이동"은 중복 항목을 제거한 후 수행됩니다.

find /var/www/domain/media/ -type f | > media
find /var/www/domain/bak/ -type f | awk '{a=gensub("bak","media",1); print a}' > bak
cat bak media | sort | uniq -d > dupes
cat dupes | xargs rm
cp -r /var/www/domain/media/* /var/www/domain/bak/
rm -rf /var/www/domain/media/*

이것을 사용할 때의 문제점은 각 사용자가 하위 디렉토리를 가지고 있다는 mv것입니다 /var/www/domain/media/. 예를 들어:

media/user13/myvideo.webm
media/user13/walk-in-the-park.webm
media/user16/cat-video.webm
media/user17/presentation-may-2016.webm

bak/user13/mountai-trip.webm
bak/user13/walk-in-the-park.webm
bak/user14/reax-the-dog.webm

이 명령 user16은 및 user17덮어쓰기를 방지해야 합니다 bak/user13/walk-in-the-park.webm.


현재 솔루션의 문제점

media/중복을 제거하는 대신 유지하고 싶습니다 . 다른 장소로 복사해도 같은 문제가 발생합니다. 낮 동안 새 파일이 나타나고 복사본을 해당 복사본과 동기화해야 하기 때문입니다.

이미 존재하는 파일을 삭제하지 않고 디렉터리 구조를 유지하면서 media/존재하지 않는 파일을 모두 이동할 수 있는 방법은 무엇입니까 ?bak/

즉, 다음을 수행하는 작업을 찾고 있습니다.

source      | destination         | action
----------- | ------------------- | ----------------------------------
file exists | file does not exist | move (`mv`), source -> destination
file exists | file exists         | do nothing, both files stay as they are
no file     | file exists         | do nothing (will not trigger)
no file     | file does not exist | do nothing (well, there's nothing to do something with!)

좀 더 우아한 솔루션을 사용해 보세요

rsync나는 우리가 이것을 할 수 있다고 믿습니다 . 알아요, --remove-source-files하지만 방법을 찾을 수 없어요아니요타임스탬프, 체크섬, 파일 크기 등을 확인하세요.

체크섬을 완전히 별도의 프로세스로 저장하고 확인하겠습니다.

파일 이름에만 관심이 있습니다. 이로 인해 파일이 손상될 수 있다는 것을 알고 있지만 RAID 서버보다는 일반 디스크에 손상된 파일을 가져오는 것이 훨씬 쉬울 것 같습니다.

rsync비 솔루션을 환영합니다. shell이동을 수행하는 스크립트를 작성하고 싶습니다 .현재 솔루션부분). 그러나 이것이 얼마나 쉽게 잘못될 수 있는지 생각하고 나서 포기했습니다.

나는 또한 다음을 시도했습니다.

tar -cf /var/www/domain/media | (cd /var/www/domain/bar; tar -kxf -)

그러나 미디어 파일(상당히 클 수 있음)의 경우 속도가 너무 느리고 모든 파일을 유지합니다 media/(디스크 공간이 제한됨).

답변1

파일이 대상 트리에 이미 있는 경우(메타데이터에 관계없이) --ignore-existing작업이 수행되지 않으면 이 옵션을 rsync에 전달합니다.

rsync -a --remove-source-files --ignore-existing /var/www/domain/media/ /var/www/domain/bak/

완전성을 기하기 위해 원본과 대상이 동일한 파일 시스템에 있는 상황을 기반으로 한 솔루션이 있습니다(이 경우 find파일을 단순히 파일 시스템으로 이동하는 대신 파일을 복사한 다음 삭제하기 때문에 좋은 솔루션이 아닙니다). 대상 디렉토리).mvrsync

cd /var/www/domain/media
find -type f -exec '
  for x; do
    if ! [ -e "/var/www/domain/bak/$x" ]; then
      mkdir -p "/var/www/domain/bak/${x%/*}" &&
      mv -- "$x" "/var/www/domain/bak/$x"
    fi
  done
' sh {} +

관련 정보