zsh에서 변수 확장

zsh에서 변수 확장

아래 스크립트는 bash에서는 작동하지만 zsh에서는 작동하지 않습니다. 나는 이것이 변수 내에서 OPTS변수를 "확장"(올바른 단어인지 확실하지 않음)하고 있고 $EXCLUDE이 구문이 zsh에서 작동하지 않기 때문이라고 생각합니다. zsh에서 작동하도록 이 줄을 어떻게 바꿀 수 있습니까?

SRC="/path_to_source"
DST="/path_to_dest"
EXCLUDE=".hg"  
OPTS="-avr --delete --progress --exclude=${EXCLUDE} --delete-excluded"                                               

rsync $OPTS $SRC $DST   

답변1

여기서 문제는 $OPTS명령줄에서 여러 매개변수로 구분되지 않는다는 것입니다 rsync. zsh구문 에서 다음을 사용합니다.

rsync ${=OPTS} $SRC $DST 

(대안은 옵션을 사용하여 전역적으로 표준 쉘 동작을 에뮬레이션하는 것입니다 -o shwordsplit...)

맨페이지에서:

[in]의 일반적인 차이점 zsh은 명령줄에서 대체된 변수가 단어로 분할되지 않는다는 것입니다. SH_WORD_SPLIT"매개변수 확장" 섹션에서 셸 옵션에 대한 설명을 참조하세요 zshexpn(1). 에서는 zsh명시적으로 분할을 요청하거나(예: ${=foo}) 변수를 여러 단어로 확장하려는 경우 배열을 사용할 수 있습니다. 의 "배열 매개변수" 섹션을 참조하십시오 zshparam(1).

답변2

문제는 에서가 $EXCLUDE아니라 에서 발생합니다 $OPTS. 귀하의 스크립트는 단어 분리 발생에 의존합니다 $OPTS. 예를 들어 현재 디렉터리에 $EXCLUDE패턴과 일치 파일을 포함하도록 변경하거나 공백을 포함하도록 --exclude=$EXCLUDE변경하면 $EXCLUDE실패합니다.

$OPTS단일 단어가 아닌 단어 목록입니다. ksh, bash 및 zsh에서만 작동하는 스크립트가 필요한 경우 이를 배열로 만듭니다.

SRC="/path_to_source"
DST="/path_to_dest"
EXCLUDE=".hg"
OPTS=(-avr --delete --progress --exclude="$EXCLUDE" --delete-excluded)
rsync "${OPTS[@]}" "$SRC" "$DST"

스크립트가 zsh에서만 작동하도록 하려면 마지막 줄을 단순화하면 됩니다.

rsync $OPTS $SRC $DST

모든 셸에서 스크립트를 실행하려면 위치 매개변수를 사용해야 합니다. 이는 사용 가능한 유일한 배열입니다.

set -- -avr --delete --progress --exclude="$EXCLUDE" --delete-excluded
rsync "$@" "$SRC" "$DST"

zsh를 사용하여 쉘 스크립트를 편리하게 실행하려면 이 줄을 시작 부분에 넣으십시오. 이는 zsh가 ksh처럼 작동하고 다른 쉘에서는 아무것도 하지 않도록 지시합니다.

emulate ksh >/dev/null 2>/dev/null || true

답변3

zshStéphane Gimenez의 답변을 완료하려면(아직 코멘트할 수 없음) 한 가지 해결책은 스크립트를 $OPTS사용하고 있는지 확인한 다음 다음과 같은 배열로 변환하여 스크립트를 bash로 이식 가능하게 만드는 것 입니다.

[ -n "${ZSH_VERSION:-}" ] && set -A OPTS ${=OPTS}

그러면 rsync 명령이 작동합니다.

관련 정보