일부 폴더를 제외하고 폴더를 재귀 적으로 복사


197

숨겨진 파일과 폴더를 포함한 폴더의 전체 내용을 다른 폴더에 복사하는 간단한 bash 스크립트를 작성하려고하지만 특정 폴더를 제외하고 싶습니다. 어떻게하면 되나요?


1
나는 find 같은 것을 상상한다. -name * grep / v "exclude-pattern"에 파이프하여 원하지 않는 것을 필터링 한 다음 cp에 파이프하여 복사합니다.
i_am_jorf

1
나는 그런 것을하려고했지만 파이프와 함께 cp를 사용하는 방법을 알 수 없었다
trobrock

1
아마도 수퍼 유저에게 가야 할 것입니다. 찾고있는 명령은 xargs입니다. 파이프로 연결된 두 개의 타르와 같은 것을 할 수도 있습니다.
Kyle Butt

1
아마도 늦었고 질문에 정확하게 대답하지 못했지만 여기에 팁이 있습니다. 디렉토리의 직계 자식 만 제외하려면 bash 패턴 일치를 활용할 수 있습니다 cp -R !(dir1|dir2) path/to/destination
.

1
노트 것을 !(dir1|dir2)패턴이 필요 extglob켜야하는 ( shopt -s extglob을 켭니다).
Boris D. Teoharov

답변:


334

rsync를 사용하십시오.

rsync -av --exclude='path1/to/exclude' --exclude='path2/to/exclude' source destination

사용합니다 sourcesource/다르다. 후행 폴더의 내용을 복사하는 수단 슬래시 source로를 destination. 슬래시가 없으면 폴더 source를에 복사하는 것을 의미합니다 destination.

또는 제외 할 디렉토리 (또는 파일)가 많은 경우를 사용할 수 있습니다 --exclude-from=FILE. 여기서 제외 할 FILE파일 또는 디렉토리를 포함하는 파일 이름입니다.

--exclude 와 같은 와일드 카드를 포함 할 수도 있습니다. --exclude=*/.svn*


10
복사 할 파일을 확인하기 위해 --dry-run을 추가하는 것이 좋습니다.
loretoparisi

1
@AmokHuginnsson-어떤 시스템을 사용하고 있습니까? RHEL, CentOS, Debian 및 Ubuntu를 포함하여 내가 아는 모든 주류 Linux 배포판에 Rsync가 기본적으로 포함되어 있으며 FreeBSD에도 있다고 생각합니다.
siliconrockstar

1
RHEL 파생 배포판 : yum install rsync 또는 Debian 기반 릴리스 : apt-get install rsync. 자체 하드웨어를 기반으로 서버를 구축하지 않는 한 이것은 문제가되지 않습니다. rsync는 기본적으로 Amazon EC2 상자와 ZeroLag 및 RackSpace의 상자에 설치됩니다.
siliconrockstar

2
rsync는 cp에 비해 매우 느린 것 같습니다. 적어도 이것은 나의 경험이었다.
Kojo

2
예를 들어 git dir을 무시하려면 :rsync -av --exclude='.git/' ../old-repo/ .
nycynik

40

파이프와 함께 타르를 사용하십시오.

cd /source_directory
tar cf - --exclude=dir_to_exclude . | (cd /destination && tar xvf - )

ssh에서이 기술을 사용할 수도 있습니다.


이 방법은 불필요하게 먼저 대상 소스를 대상으로 설정하고 (아카이브에서 특정 디렉토리를 제외) 대상에서 대상을 압축 해제합니다. 추천하지 않습니다!
Wouter Donders

4
@ Waldheri 당신이 잘못되었습니다. 이것이 가장 좋은 해결책입니다. OP가 요청한 것과 정확히 일치하며 OS와 같은 대부분의 * nix 기본 설치에서 작동합니다. taring 및 untaring은 파일 시스템 아티팩트 (메모리에 없음)없이 즉시 수행되므로이 ​​tar + untar의 비용은 무시할 수 있습니다.
AmokHuginnsson

@WouterDonders Tar은 최소한의 오버 헤드입니다. 압축을 적용하지 않습니다.
Kyle Butt

9

옵션 find과 함께 사용할 수 있습니다 -prune.

예를 들면 다음과 man find같습니다.

       cd / source-dir
       찾기 . -name .snapshot -prune -o \ (\! -name * ~ -print0 \) |
       cpio -pmd0 / dest-dir

       이 명령은 / source-dir의 내용을 / dest-dir에 복사하지만 생략합니다.
       이름이 .snapshot 인 파일 및 디렉토리 또한
       ~로 끝나는 파일이나 디렉토리는 생략하지만 그 이름은 ~
       텐트. -prune -o \ (... -print0 \) 구문은 매우 일반적입니다. 그만큼
       여기서 아이디어는 정리 전의 표현은
       가지 치기. 그러나 -prune 조치 자체는 true를 리턴하므로
       다음 -o는 오른쪽이 다음에 대해서만 평가되도록합니다.
       정리되지 않은 디렉토리 (제거 된 내용)
       디렉토리도 방문하지 않으므로 내용은 관련이 없습니다).
       -o의 오른쪽에있는 표현식은 괄호 안에 있습니다.
       명확성을 위해. -print0 조치 만 발생 함을 강조합니다.
       자두가 적용되지 않은 것들에 대해. 때문에
       테스트 사이의 기본`and '조건은 -o보다 더 밀접하게 바인딩됩니다.
       어쨌든 기본값이지만 괄호는 무슨 일이 일어나고 있는지 보여줍니다.
       의 위에.

맨 페이지에서 직접 관련성이 높은 예제를 찾기위한 소품.
David M

실제로 좋아 보인다! 온라인 문서 에서도 제공 됩니다. . 불행히도 cpio아직 MSYS2 용으로 패키지되지 않았습니다.
underscore_d

3

--exclude 옵션과 함께 tar를 사용한 다음 대상에서 untar 할 수 있습니다. 예 :

cd /source_directory
tar cvf test.tar --exclude=dir_to_exclude *
mv test.tar /destination 
cd /destination  
tar xvf test.tar

자세한 내용은 tar 매뉴얼 페이지를 참조하십시오


2

Jeff의 아이디어와 비슷합니다 (예상치 않음).

find . -name * -print0 | grep -v "exclude" | xargs -0 -I {} cp -a {} destination/

죄송하지만, 5 명이 승인되지 않았을 때 왜 이것을 공표했는지, 간단한 테스트에서는 효과가없는 것 같습니다. 나는 이것을 하위 디렉토리에서 시도 하고 후자가 하위 디렉토리 중 하나 인 곳을 /usr/share/icons즉시 얻었습니다 find: paths must precede expression: 22x22. . 내 명령은 find . -name * -print0 | grep -v "scalable" | xargs -0 -I {} cp -a {} /z/test/(실제로 MSYS2에 /mingw64/share/icons/Adwaita있지만 실제로 는 MSYS2의 결함인지 알 수 없음)
underscore_d

0
EXCLUDE="foo bar blah jah"                                                                             
DEST=$1

for i in *
do
    for x in $EXCLUDE
    do  
        if [ $x != $i ]; then
            cp -a $i $DEST
        fi  
    done
done

테스트되지 않은 ...


이것은 올바르지 않습니다. 몇 가지 문제점 : 작성된대로 여러 번 제외되지 않아야하는 파일 (이 경우 제외 할 항목 수)은 4입니다. 제외 목록의 첫 번째 항목 인 'foo'를 복사하려고 시도하더라도 x = bar에 도달해도 i는 여전히 foo입니다. 기존 도구 (예 : rsync)없이이 작업을 수행하려면 복사본을 'for x in ...'루프 외부의 if 문으로 이동하고 'for x ...'루프에서 논리 문을 변경하십시오. if (true) 복사 파일 여러 번 복사하지 못하게됩니다.
Eric Bringley

0

실패 SteveLazaridis의 대답은, @ 영감, 여기 POSIX 쉘 기능입니다 - 그냥 복사 및 붙여 넣기라는 이름의 파일로 cpx행해져 Yout에 $PATH하고 executible 수 있도록 ( chmod a+x cpr). [소스는 이제 내 GitLab 에서 유지 관리됩니다 .

#!/bin/sh

# usage: cpx [-n|--dry-run] "from_path" "to_path" "newline_separated_exclude_list"
# limitations: only excludes from "from_path", not it's subdirectories

cpx() {
# run in subshell to avoid collisions
  (_CopyWithExclude "$@")
}

_CopyWithExclude() {
  case "$1" in
    -n|--dry-run) { DryRun='echo'; shift; } ;;
  esac

  from="$1"
  to="$2"
  exclude="$3"

  $DryRun mkdir -p "$to"

  if [ -z "$exclude" ]; then
      cp "$from" "$to"
      return
  fi

  ls -A1 "$from" \
    | while IFS= read -r f; do
        unset excluded
        if [ -n "$exclude" ]; then
          for x in $(printf "$exclude"); do
          if [ "$f" = "$x" ]; then
              excluded=1
              break
          fi
          done
        fi
        f="${f#$from/}"
        if [ -z "$excluded" ]; then
          $DryRun cp -R "$f" "$to"
        else
          [ -n "$DryRun" ] && echo "skip '$f'"
        fi
      done
}

# Do not execute if being sourced
[ "${0#*cpx}" != "$0" ] && cpx "$@"

사용법 예

EXCLUDE="
.git
my_secret_stuff
"
cpr "$HOME/my_stuff" "/media/usb" "$EXCLUDE"

무엇이 잘못되었고 어떻게 고쳐야하는지 설명하지 않고 누군가의 대답이 "실패 할 것"이라고 말하는 것은 도움이되지 않는 것 같습니다 ...
underscore_d

@underscore_d : 사실, 실패한 것을 기억할 수없는 사실로 가늠할 때 esp :-(
go2null

여러 가지 : (1) 파일을 여러 번 복사하고 (2) 논리는 여전히 제외 할 파일을 복사합니다. i = foo를 사용하여 루프를 실행합니다. 다른 파일 (예 : i = test.txt)에 대해서는 4 대신 3 번 복사됩니다.
Eric Bringley

1
Steve의 답변의 단점을 분명히 해주신 @EricBringley에게 감사드립니다. (그는 그것이 테스트되지 않았다고 말했다 .)
go2null
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.