동적 rsync 명령에서 큰따옴표를 이스케이프합니다.

동적 rsync 명령에서 큰따옴표를 이스케이프합니다.

현재 사용자의 홈 디렉터리를 임의로 선택한 디렉터리에 복사하고 rsync를 사용하여 동일한 디렉터리(존재하는 경우)에서 가장 최근에 생성된 복사본에 연결하는 스크립트를 작성 중입니다.

명령은 다음과 같이 빌드되고 실행됩니다.

...
[ -z $LAST_SNAPSHOT ] && LINK_DEST="" || LINK_DEST="--link-dest \"$BACKUP_ROOT/$LAST_SNAPSHOT\""
...

/usr/bin/rsync $OPTS $EXCLUDES $LINK_DEST "$MASTER/" "$NEW_SNAPSHOT"

rsync 스크립트를 실행하면 다음 오류가 발생합니다.

--link-dest arg does not exist: "/home/backuptest/dest/backuptest/20180619_134044"

이는 디렉토리가 실제로 존재하지 않지만 존재하는 경우 예상됩니다.

변수를 생성하는 코드에서 따옴표를 제거하면 $LINK_DEST다음 코드가 생성됩니다.

[ -z $LAST_SNAPSHOT ] && LINK_DEST="" || LINK_DEST="--link-dest $BACKUP_ROOT/$LAST_SNAPSHOT"

그러면 rsync가 불평하지 않습니다. 경로에 공백이 없도록 하고 싶으므로 큰따옴표가 필요합니다.

오류가 무엇인지 이해할 수 없습니다. rsync를 호출하는 방식인가요, 아니면 쉘(bash)을 오해하고 있는 건가요?

답변1

이스케이프된 큰따옴표는 파일 이름의 리터럴 문자로 처리됩니다. 를 사용하고 있으므로 bash배열을 사용하여 이를 처리할 수 있습니다.

linkDest=()
[[ -n "$LAST_SNAPSHOT" ]] && linkDest+=('--link-dest' "$BACKUP_ROOT/$LAST_SNAPSHOT")
...

rsync $OPTS $EXCLUDES "${linkDest[@]}" "$MASTER/" "$NEW_SNAPSHOT"

"${linkDest[@]}"참조가 비어 있으면 참조가 완전히 사라집니다. 그렇지 않으면 해당 값의 참조 목록으로 확장됩니다. $OPTS과 가 목록 이었다면 $EXCLUDES동일한 메커니즘을 사용할 것입니다.

답변2

문제는 파일 이름의 일부로 큰따옴표가 있다는 것입니다.

옵션을 저장하려면 배열을 사용하십시오 rsync.

셸 에서 /bin/sh(셸에서도 작동 가능 bash):

# options that are always set
set -- --archive --verbose

# add --link-dest=DIR if needed
if [ -n "$LAST_SNAPSHOT" ]; then
    set -- "$@" --link-dest="$BACKUP_ROOT/$LAST_SNAPSHOT"
fi

# add some --excludes
set -- "$@" --exclude='*.ext' --exclude='dir/***'

# call rsync
rsync "$@" "$MASTER/" "$NEW_SNAPSHOT"

bash이는 위치 인수 배열인 POSIX 셸에서 사용할 수 있는 유일한 배열(확장, 유사 등이 아닌 경우)을 활용합니다 . 이 배열의 항목을 설정하고( 를 사용하여 set) 필요에 따라 추가함으로써 rsync인용된 인수(또는 모든 명령)가 올바르게 처리되도록 할 수 있습니다. 호출에서 배열의 항목이 큰따옴표로 개별적으로 묶여 있는지 rsync확인 "$@"하여 쉘이 파일 이름을 토큰화하고 생성하는 것을 방지합니다.

동등한 것이지만 bash배열을 사용하는 경우:

# options that are always set
opts=( --archive --verbose )

# add --link-dest=DIR if needed
if [ -n "$LAST_SNAPSHOT" ]; then
    opts+=( --link-dest="$BACKUP_ROOT/$LAST_SNAPSHOT" )
fi

# add some --excludes
opts+=( --exclude='*.ext' --exclude='dir/***' )

# call rsync
rsync "${opts[@]}" "$MASTER/" "$NEW_SNAPSHOT"

답변3

차이점은 이스케이프 따옴표가 \"이를 문자열 문자로 변환한다는 것입니다.

따라서 오류가 정확할 수 있습니다.

"/홈/백업테스트/대상/백업테스트/20180619_134044"

이름에서 따옴표가 포함된 부분은 다음과 같습니다.

/홈/백업 테스트/대상/백업 테스트/20180619_134044

이것이 당신이 원하는 것입니다. 이 문제를 해결하기 위해 권장되는 방법은 ${} 변수를 사용하는 것입니다. 예를 들면 다음과 같습니다. $ myvar=var $ echo "\"$myvar\"" "var" $ echo "${myvar}" var

따라서 "--link-dest "${BACKUP_ROOT}"/"${LAST_SNAPSHOT}""과 같은 명령을 사용하면 더 가까워질 것입니다.

이 콘텐츠에 대한 추가 정보: https://stackoverflow.com/questions/8748831/when-do-we-need-curly-braces-around-shell-variables 그리고 http://wiki.bash-hackers.org/syntax/pe#simple_usage

관련 정보