MV와 폴더를 병합 하시겠습니까?


149

mv"폴더"라는 폴더를 이미 "폴더"가 포함 된 디렉토리로 이동하는 경우 병합되거나 대체됩니까?

답변:


120

mv디렉토리를 병합하거나 덮어 쓸 수없는 경우 --force옵션을 사용하더라도 "mv : 'a'를 'b'로 이동할 수 없습니다 : 디렉토리가 비어 있지 않습니다" 라는 메시지와 함께 실패 합니다 .


다른 도구 (예 rsync: find, 또는 cp)를 사용하여이 문제를 해결할 수 있지만 그 의미를 신중하게 고려해야합니다.

  • rsync합니다 (이상적으로 다른에 하나의 디렉토리의 내용을 병합 할 수 있습니다 --remove-source-files(1 개) 안전에만 성공적으로 전송 된 그 소스 파일을 삭제하는 옵션, 그리고 보통의 허가 / 소유 / 시간 보존 옵션을 사용하여 -a당신이 원하는 경우)
    ... 그러나 이것은 전체 복사 작업입니다 따라서 디스크를 많이 사용합니다.
  • 현재 원하는 옵션 : 당신은 결합 할 수 rsync--link-dest=DIR및 (가능한 대신 복사 파일 내용의 하드 링크 생성하기) 옵션을 --remove-source-files일반에 대한 의미와 매우 유사 얻을 수를 mv.
    이를 위해 소스 디렉토리에 --link-dest대한 절대 경로 (또는 대상 에서 소스 까지의 상대 경로)를 제공해야 합니다 . … 그러나 이것은 의도하지 않은 방식으로 (합병증을 유발하거나 유발하지 않을 수 있음) 사용하고 있으며 소스에 대한 절대 경로를 알고 (또는 결정하는) 필요 하며 빈 디렉토리 구조를 다시 정리합니다. 당 1 .
    --link-dest--link-dest
  • 당신은 사용할 수 있습니다find 개별적 실제 파일을 이동 대상에서 소스 디렉토리 구조를 다시 순차적으로
    ... 하지만 이 소스를 여러 번을 통해 재귀해야하고 경쟁 조건 (새 디렉토리가 여러 단계의 과정 소스에서 생성되는 발생할 수 있습니다 )
  • cp하드 링크를 만들 수 있습니다 병합과 매우 유사한 결과를 생성, (단순히 같은 기존 파일에 추가 포인터를 넣어) mv(만 포인터가 생성되고 실제 데이터를 복사 할 수 없습니다 때문에 매우 IO-효율적입니다)
    ... 하지만 이 가능한 경쟁 조건으로 인해 다시 발생합니다 (이전 단계에서 복사되지 않았더라도 소스의 새 파일이 삭제됨)

이러한 해결 방법 (있는 경우) 중 적절한 것은 사용 사례에 따라 크게 다릅니다.
항상 그렇듯이 이러한 명령을 실행하고 백업을하기 전에 생각하십시오.


1 : rsync --remove-source-files디렉토리를 삭제하지 않으므로 find -depth -type d -empty -delete빈 소스 디렉토리 트리를 제거하려면 나중에 같은 작업을 수행해야합니다 .


하나의 구현을 시도한 것 같습니다 mv. 이 대답은 더 넓은 진실로 더 나을 것입니다. Linux, BSD 및 "real"Unix 또는 POSIX 또는 SUS의 참조.
Warren Young

@WarrenYoung 네 말이 맞아, 난 단지 시도 mv데비안에서 사용하는 구현을 - 강조가에있는 시도 맨 페이지가이 문제를 언급하지 않기 때문에 ...
n.st

38
rsync의 단점은 하드 링크를 변경하는 대신 실제로 데이터를 복사한다는 것입니다. 많은 데이터를 처리하는 경우 잠재적으로 리소스를 많이 사용합니다.
Jonathan Mayer

7
@Keith 소스 디렉토리에 존재하지 않는 대상 디렉토리의--delete 파일 만 삭제합니다 .
n.st

1
@JonathanMayer는 여러 하드 링크 관련 기능으로 rsync합니다. 예를 들어 -H함수를 사용하여 하드 링크를 유지 하거나을 사용하여 대상의 파일을 하드 링크 할 수 있습니다 --link-dest. 그러나 사용하기 전에 매뉴얼 페이지를 참조하십시오.
allo

87
rsync -av /source/ /destination/
(after checking)
rm -rf /source/

이것은 n.st의 주석과 같은 소스 파일을 제거합니까?
Dominique

3
아니요, 안전상의 이유로 두 단계로 만드는 것이 좋습니다. 병합 및 제거 된 소스는 되돌릴 수 없습니다. n.st anwer의 Additon 단계도 필요합니다 (디렉토리 제거).
fazie

3
--remove-source-files성공적으로 전송 된 파일 만 제거 할 수 있다는 장점이 있으므로 find빈 디렉토리를 제거 하는 데 사용할 수 있으며 rsync출력 을 확인하지 않고도 전송되지 않은 모든 항목이 남습니다 .
n.st

4
그러나 실제로는 움직이지 않습니다. 큰 파일이 포함되면 속도에 큰 영향을 미칩니다.
Alex

그러나 실제로 순수한 이동과 병합을 수행 할 수는 없습니다.
fazie

64

cp 명령 의 -l옵션을 사용하면 전체 데이터 사본 대신 동일한 파일 시스템에 파일의 하드 링크 가 작성 됩니다. 다음 명령은 폴더 를 이미 이름이있는 디렉토리를 포함하는 상위 폴더 ( )에 복사합니다 .source/folderdestinationfolder

cp -rl source/folder destination
rm -r source/folder

필요에 따라 -P( --no-dereference-심볼릭 링크를 역 참조하지 않음) 또는 -a( --archive-모든 메타 데이터 유지, -P옵션 포함)을 사용할 수도 있습니다 .


7
@rautamiekka : 하드 링크를 사용하는 이유를 묻고 있다고 가정합니다. 하드 링크가 무엇이며 왜 사용해야하는지 모르는 경우이 경로를 사용하지 않아야합니다. 그러나 하드 링크를 만들면 전체 복사본이 수행되지 않으므로이 작업은 전체 복사본보다 몇 배나 적은 시간이 걸립니다. 또한 소프트 링크 대신 하드 링크를 사용하여 소스 파일을 삭제하고 유효하지 않은 경로에 대한 포인터 대신 올바른 데이터를 유지할 수 있습니다. 그리고 모든 시스템에 모든 사람이 익숙 cp하기 rsync때문에 그보다는 오히려 cp.
palswim

7
이 솔루션의 광채는 인정되는 답변이 아닌 것으로 간과 될 수 있습니다. 우아한 솔루션입니다. cp의 작업 시간과 의 병합 능력을 얻습니다 mv.
TheHerk

2
목적지에 이미 존재하는 파일을 이동할 필요가 없다는 것을 알고 있다면 추가하고 싶은-n
ndemou

1
@Ruslan : 이것은 사실이지만 어떤 방법으로도 파일 시스템간에 복사없이 이동할 수 없습니다. 심지어 mv /fs1/file /fs2/(파일 시스템에서)를 복사 한 후 삭제를 수행합니다.
palswim 2016 년

2
맞지만, mv"효율적으로"또는 호출하지 않더라도 작동 하지만 (대상 디렉토리가 존재하지 않는 경우) 작동하지 않습니다 cp -rl.
Ruslan

23

다음 4 단계를 권장합니다.

cd ${SOURCE}; 
find . -type d -exec mkdir -p ${DEST}/\{} \; 
find . -type f -exec mv \{} ${DEST}/\{} \; 
find . -type d -empty -delete

또는 더 나은 방법은 mv다음 과 유사한 의미를 구현하는 스크립트입니다 .

#!/bin/bash

DEST="${@:${#@}}"
ABS_DEST="$(cd "$(dirname "$DEST")"; pwd)/$(basename "$DEST")"

for SRC in ${@:1:$((${#@} -1))}; do   (
    cd "$SRC";
    find . -type d -exec mkdir -p "${ABS_DEST}"/\{} \;
    find . -type f -exec mv \{} "${ABS_DEST}"/\{} \;
    find . -type d -empty -delete
) done

Args are SOURCE, DEST
schuess

이것은 매우 유용하게 보입니다. 하드 드라이브를 정리할 때 사용하고 싶습니다. 이 스크립트에 백업을 위임하기 전에 다른 전문가가 의견을 말할 수 있습니까? :-)
LarsH 2016 년

BTW, rsync -u(최신 버전의 경우에만 업데이트) 와 동등한 작업을 수행하려는 경우 mv(일부 버전에서는) -u옵션을 사용할 수도 있습니다 . 그러나이 경우 비어 있지 않은 소스 디렉토리와 비어있는 디렉토리를 삭제하여 소스 트리의 파일이 최신이 아닌 경우를 포함 할 수 있습니다. @ schuess : 필요한 경우 여러 개의 SOURCE 인수가있을 수 있습니다.
LarsH 2016 년

1
공백을 잘 처리하지 못합니다. 공백이있는 일부 디렉토리로 시도해보고 무한한 일련의 중첩 디렉토리로 끝났습니다.
rofer

16

디렉토리를 병합하는 방법은 다음과 같습니다. 파일을 복사 한 다음 삭제하는 대신 파일 이름을 변경하기 때문에 rsync보다 훨씬 빠릅니다.

cd source; find -type f -print0 | xargs -0 -n 1 -I {} mv '{}' 'dest/{}'

그것은 흥미롭지 만 주제와 모호하게 관련이 있으며 사용자가 요청한 내용조차도 원격이 아닙니다.
Shadur

17
실제로 Jewel의 코드는 누락 된 디렉토리를 제외하고 사용자가 요청한 내용을 정확하게 수행합니다. 아마도 다시 봐야할까요?
Jonathan Mayer

3
이름에 공백이있는 파일이 있기 때문에 찾기에서 "-print0"을 사용하고 xargs에서 "-0"을 사용하도록 추가합니다. 또한 작은 문제가 있는데, 이름에 괄호가 포함되어 있으면 이동할 수 없습니다.
markuz

2
이것은 적은 수의 파일에 대해서는 rsync보다 훨씬 빠르지 만 모든 파일에 대해 새로운 프로세스를 수행하므로 많은 수의 작은 파일로 인해 성능이 크게 저하됩니다. @palswim의 대답은이 문제로 고통받지 않습니다.
b0fh

2
in dest이 이미와 이름이 같은 디렉토리 인 경우 명령이 실패 source합니다. 그리고 파일은로 이동합니다 dest에 인 source. 이 명령은 더 이상 아무것도하지 않습니다mv source/* source/dest/.
13:25에

3

이를 달성하는 한 가지 방법은 다음을 사용하는 것입니다.

mv folder/* directory/folder/
rmdir folder

folder및에 동일한 이름을 가진 두 파일이없는 directory/folder한 동일한 결과 (예 : 병합)를 얻을 수 있습니다.


3
정확히 어떻게 rm folder작동합니까?
JakeGould

5
@JakeGould 전혀 아닙니다. :)
n.st

rm folder -fR항상 나를 위해 작동
Octopus

2
이 숨겨진 파일에 대해 작동하지 않습니다주의
b0fh

2

가장 순수한 사본의 경우 tar (-) B blockread copy 방법을 사용합니다.

예를 들어, 소스 경로 내에서 (필요한 경우 'cd') :

tar cBf - <sourcefolder> | (cd /your/target/folder ; tar xBf -)

소유자와 권한이 그대로있는 소스 트리의 정확한 사본이 생성됩니다. 대상 폴더가 있으면 데이터가 병합됩니다. 이미 존재하는 파일 만 덮어 씁니다.

예:

 $ cd /data1/home
 $ tar cBf - jdoe | (cd /data2/home ; tar xBf -)

복사 작업이 성공하면 소스 ( rm -rf <source>)를 제거 할 수 있습니다 . 물론 이것은 정확한 이동이 아닙니다. 소스를 제거 할 때까지 데이터가 복사됩니다.

옵션으로 -v를 사용하여 자세한 내용을 볼 수 있습니다 (복사중인 파일을 화면에 표시). tar cBvf -

  • c: 창조하다
  • B: 전체 블록 읽기 (파이프 읽기 용)
  • v: 자세한
  • f: 쓸 파일
  • x: 추출
  • -: stdout / stdin

sourcefolder또한 일 수있다 *(현재 폴더에 아무것도)


f -tar로 지정 하는 것은 일반적으로 불필요합니다. 기본값은 stdin / write에서 stdout으로 읽는 것입니다.
muru

1

여기 나를 위해 일한 스크립트가 있습니다. rsync보다 mv를 선호하므로 Jewel과 Jonathan Mayer의 솔루션을 사용합니다.

#!/bin/bash

# usage source1 .. sourceN dest

length=$(($#-1))
sources=${@:1:$length}
DEST=$(readlink -f ${!#})
for SRC in $sources; do
    pushd $SRC;
    find . -type d -exec mkdir -p ${DEST}/{} \;
    find . -type f -exec mv {} ${DEST}/{} \;
    find . -type d -empty -delete
    popd
done

이 솔루션은 경로 이름을 올바르게 이스케이프하지 않으므로주의하십시오.
user12439

@ user12439, 수정해야 할 부분을 보여 주면 솔루션을 업데이트 할 것입니다.
xer0x

1

cp 또는 rsync와 같은 명령을 사용하는 것은 좋지 않습니다. 큰 파일의 경우 시간이 오래 걸립니다. mv는 파일을 물리적으로 복사하지 않고 inode 만 업데이트하기 때문에 훨씬 빠릅니다. 더 나은 옵션은 운영 체제의 파일 관리자를 사용하는 것입니다. Opensuse의 경우 Konquerer라는 파일 관리자가 있습니다. 실제로 복사하지 않고 파일을 이동할 수 있습니다. Windows에서와 같이 "잘라 내기 및 붙여 넣기"기능이 있습니다. 디렉토리 A에서 모든 서브 디렉토리를 선택하십시오. 동일한 이름의 서브 디렉토리를 포함 할 수있는 디렉토리 B를 마우스 오른쪽 단추로 클릭하고 "이동"하십시오. 그것들을 병합합니다. 이름이 같은 파일을 덮어 쓰거나 이름을 바꾸려는 옵션도 있습니다.


1
OP mv는 사용될 때 어떤 일이 발생하는지 묻습니다 .
don_crissti

0

파이썬 솔루션

만족스러운 기존 솔루션을 찾을 수 없으므로 빠른 Python 스크립트를 작성하여이를 달성하기로 결정했습니다.

특히이 방법은 소스 파일 트리를 한 번만 위로 올라가므로 효율적입니다.

또한 파일 덮어 쓰기 처리와 같은 항목을 원하는대로 신속하게 조정할 수 있습니다.

용법:

move-merge-dirs src/ dest/

모든 내용을 이동 src/*로를 dest/하고 src/사라집니다.

이동 병합 디렉토리

#!/usr/bin/env python3

import argparse
import os

def move_merge_dirs(source_root, dest_root):
    for path, dirs, files in os.walk(source_root, topdown=False):
        dest_dir = os.path.join(
            dest_root,
            os.path.relpath(path, source_root)
        )
        if not os.path.exists(dest_dir):
            os.makedirs(dest_dir)
        for filename in files:
            os.rename(
                os.path.join(path, filename),
                os.path.join(dest_dir, filename)
            )
        for dirname in dirs:
            os.rmdir(os.path.join(path, dirname))
    os.rmdir(source_root)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Move merge src/* into dest. Overwrite existing files.'
    )
    parser.add_argument('src_dir')
    parser.add_argument('dest_dir')
    args = parser.parse_args()
    move_merge_dirs(args.src_dir, args.dest_dir)

GitHub의 업스트림 .

참조 : https : //.com/questions/22588225/how-do-you-merge-two-directories-or-move-with-replace-from-the-windows-command


0

파일 및 폴더를 다른 대상으로 이동하는 명령입니다.

$ mv /source/path/folder /target/destination/

기억하십시오 : mv폴더가 b̲e̲i̲n̲g m̲e̲r̲ge̲d̲ (예 : 동일한 이름을 가진 다른 폴더가 대상에 이미 존재 함)이고 d̲e̲s̲t̲i̲n̲a̲t̲i̲o̲n̲ o̲n̲e̲ i̲s̲ n̲o̲t̲ e̲m̲pt̲y 이면 명령이 작동 하지 않습니다 .

mv : '/ source / path / folder'를 '/ target / destination / folder'로 이동할 수 없습니다 : 디렉토리가 비어 있지 않습니다

대상 폴더가 비어 있으면 위의 명령이 제대로 작동합니다.

따라서 두 경우 모두 두 폴더를 병합하려면 두 가지
명령으로 수행하십시오.

$ cp -rf /source/path/folder /target/destination/
$ rm -rf /source/path/folder

또는 일회성 명령으로 두 가지를 결합하십시오.

$ cp -rf /source/path/folder /target/destination/ && rm -rf /source/path/folder

mv = 이동
cp = 복사
rm = 제거

디렉토리 (폴더)의 경우 -r
-f 강제 실행

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.