변수를 사용하여 rsync를 통해 여러 디렉터리 제외

변수를 사용하여 rsync를 통해 여러 디렉터리 제외

다음 코드 조각은 제가 작업 중인 더 큰 Bash 스크립트의 일부입니다.내 목적은 입력 변수를 Rsync에 매개 변수로 전달하는 것입니다.

"--exclude" 인수를 제외하고는 대부분 작동하도록 만들었습니다.

INCLUDE="/.vim*,/.git*,/.ssh,.bash_aliases,.bashrc"  

rsync ${DRYRUNARG} -avzhP --delete ${SOURCE_DIRS} \                                                 
    --include=${INCLUDE} \                                                                          
    --exclude={/VirtualBox_VMs/*/Snapshots,/snap,/Downloads,/.*} \                                  
    ${MNTPNT}${DEST_DIR}

이 코드는 내 요구 사항에 매우 적합하지만 변수로 정의해야 하는 제외된 디렉터리를 계속 보고 싶습니다.

필요한 결과 코드는 다음과 같아야 합니다.

INCLUDE="/.vim*,/.git*,/.ssh,.bash_aliases,.bashrc"
EXCLUDE="/VirtualBox_VMs/*/Snapshots,/snap,/Downloads,/.*"       

rsync ${DRYRUNARG} -avzhP --delete ${SOURCE_DIRS} \                                                 
    --include=${INCLUDE} \                                                                          
    --exclude=${EXCLUDE} \                                  
    ${MNTPNT}${DEST_DIR}

위의 코드는 작동하지 않습니다. 명령은 오류 없이 실행되지만 아무것도 제외할 수 없습니다.흥미롭게도 하나의 디렉터리로 EXCLUDE 변수를 정의하면 INCLUDE 변수에 사용된 것과 동일한 구조를 따르더라도 작동합니다.

나는 몇 가지 어리석은 실수를 저질렀다고 확신합니다. 어디에 있을 수 있나요?

답변1

별도의 항목 목록을 단일 문자열로 축소하지 마십시오. 이로 인해 다양한 항목을 구문 분석하기가 어렵고 구분 기호 등으로 사용되는 문자가 포함될 수 있는 항목을 처리해야 합니다. 또한 rsync쉼표로 구분된 포함/제외 패턴 목록을 구문 분석하는 방법을 잘 모르겠습니다.

대신 배열을 사용하세요.

#!/bin/bash

INCLUDE=( '/.vim*' '/.git*' /.ssh .bash_aliases .bashrc )
EXCLUDE=( '/VirtualBox_VMs/*/Snapshots'  /snap /Downloads '/.*' )

그런 다음 다음 목록의 각 항목 앞에 합계를 삽입하여 --exclude새 목록을 만듭니다 .--include

exclude_opts=()
for item in "${EXCLUDE[@]}"; do
    exclude_opts+=( --exclude="$item" )
done

include_opts=()
for item in "${INCLUDE[@]}"; do
    include_opts+=( --include="$item" )
done

그런 다음 호출에서 다음 새 목록을 사용하십시오 rsync(이것이 SOURCE_DIRS소스 디렉터리의 배열이라고 가정).

rsync ${DRYRUNARG:+"$DRYRUNARG"} -avzhP --delete \
    "${include_opts[@]}" \
    "${exclude_opts[@]}" \
    "${SOURCE_DIRS[@]}" \
    "$MNTPNT/$DEST_DIR"

여기에서 $DRYRUNARG설정되고 비어 있지 않으면 따옴표로 묶이고, 그렇지 않으면 명령줄의 일부가 전혀 아닙니다.

답변2

한 가지 방법은 변수를 파일 입력으로 사용하는 것입니다 --exclude-from. 예를 들면 다음과 같습니다.

EXCLUDE_DIRS="VirtualBox_VMs
Downloads
Snapshots"

rsync  -arv --exclude-from=<(printf "%s" "$EXCLUDE_DIRS";)  $SOURCE $DESTINATION

답변3

나는 같은 것을 시도 해왔다. 그리고 이 질문이 혼란스럽다는 것을 알았습니다.

내가 할 수 있는 최선의 방법은 /bin/bash쉼표로 구분된 목록을 쉼표로 구분된 목록으로 변환하는 것입니다(사용) --exclude.

INCLUDE="/.vim*,/.git*,/.ssh,.bash_aliases,.bashrc"
EPATHS=("/VirtualBox_VMs/*/Snapshots" "/snap" "/Downloads" "/.*")     

for path in "${EPATHS[@]}"; do
   EXCLUDE="$EXCLUDE --exclude=$path"
done

rsync -avzhP --delete ${SOURCE_DIRS} \                                                 
    --include=${INCLUDE} \                                                                          
    $EXCLUDE             \                                  
    ${MNTPNT} ${DEST_DIR}

이는 불완전하고 우아하지 않은 솔루션이지만 작동합니다.

남아있는 문제는 경로 이름에 공백을 사용하여 작동하도록 할 수 없다는 것입니다. 연결에 따옴표를 추가하려고 하면예를 들어

EXCLUDE="$EXCLUDE --exclude=\"$path\""

bash더 많은 작은따옴표를 사용하면 문제가 해결되는 것 같습니다.

언급했듯이 set -x이 사람은 내 친구입니다.

관련 정보