Expandindo variáveis no zsh

5

O script abaixo funciona no bash, mas não no zsh. Eu acho que é porque na variável OPTS , eu estou "expandindo" (não tenho certeza se esta é a palavra certa) a variável $EXCLUDE , e esta sintaxe não funciona em zsh. Como eu substituiria essa linha para que funcionasse no zsh?

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

rsync $OPTS $SRC $DST   
    
por Amelio Vazquez-Reina 27.08.2011 / 02:07

3 respostas

7

O problema aqui é que $OPTS não é dividido em vários argumentos na linha de comando rsync . Na sintaxe zsh , use:

rsync ${=OPTS} $SRC $DST 

(uma alternativa é simular globalmente o comportamento padrão do shell com a opção -o shwordsplit …)

Na página de manual:

One commonly encountered difference [in zsh] is that variables substituted onto the command line are not split into words. See the description of the shell option SH_WORD_SPLIT in the section 'Parameter Expansion' in zshexpn(1). In zsh, you can either explicitly request the splitting (e.g. ${=foo}) or use an array when you want a variable to expand to more than one word. See the section 'Array Parameters' in zshparam(1).

    
por 27.08.2011 / 02:56
4

O problema não vem de $EXCLUDE , vem de $OPTS . Seu script depende da divisão de palavras acontecendo com $OPTS . Esta é uma má ideia; por exemplo, ele falhará se você alterar $EXCLUDE para conter um padrão e --exclude=$EXCLUDE corresponder a um arquivo no diretório atual ou se você alterar $EXCLUDE para conter espaço em branco.

$OPTS é uma lista de palavras, não uma palavra. Se você precisa apenas que seu script funcione em ksh, bash e zsh, crie uma matriz:

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

Se você pretende apenas que o script funcione no zsh, você pode simplificar a última linha:

rsync $OPTS $SRC $DST

Se você quiser que o script funcione em todos os shell, você precisa usar os parâmetros posicionais. Eles são o único array disponível.

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

Se você tem um shell script que você quer rodar convenientemente com zsh, coloque essa linha no começo - ele diz ao zsh para agir como ksh, e não funciona em outros shells.

emulate ksh >/dev/null 2>/dev/null
    
por 27.08.2011 / 19:47
3

Para completar a resposta de Stéphane Gimenez (ainda não posso comentar), uma solução é tornar o seu script portátil para bash verificando se você está usando zsh e então transformar $OPTS em uma matriz como esta

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

Então o seu comando rsync funcionará.

    
por 04.05.2012 / 10:31

Tags