Escapando aspas duplas no comando rsync dinâmico

1

Estou construindo um script que deve duplicar o diretório home dos usuários atuais para um diretório selecionado arbitrariamente, vinculando à duplicata criada mais recentemente no mesmo diretório, se houver, usando o rsync.

O comando é construído e executado da seguinte maneira:

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

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

Quando executo o script, o rsync me apresenta o seguinte erro:

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

Isso seria esperado se o diretório não existisse, mas funciona.

Se eu remover as aspas no código criando a variável $LINK_DEST , gerando o seguinte código

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

então o rsync não reclama. Eu gostaria de me proteger contra qualquer espaço em branco no caminho, então eu realmente preciso dos double qoutes.

Não consigo grok onde está o erro. É com como eu chamo rsync ou eu entendo errado o shell (bash) de alguma forma?

    
por fuumind 19.06.2018 / 14:30

3 respostas

1

As aspas duplas com escape estão sendo tratadas como caracteres literais do nome do arquivo. Como você está usando bash , pode usar suas matrizes para lidar com isso.

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

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

A cota "${linkDest[@]}" desaparece completamente se estiver vazia. Caso contrário, é expandido em uma lista de seus valores. Se $OPTS e $EXCLUDES também forem listas, usaria o mesmo mecanismo para elas.

    
por 19.06.2018 / 18:28
1

A questão é que você fez as aspas duplas no nome do arquivo.

Use uma matriz para manter as opções em rsync .

Em um shell /bin/sh (também funcionaria em 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"

Isso faz uso do único array disponível em um shell POSIX (a menos que estendido, como bash e outros), o array de parâmetros posicionais. Ao definir as entradas nessa matriz (usando set ) e adicioná-las conforme necessário, podemos ter certeza de manipular argumentos citados para rsync (ou qualquer comando) apropriadamente. Na chamada para rsync , usamos "$@" , o que garantirá que as entradas na matriz sejam individualmente citadas duplamente e, portanto, protegidas da divisão de palavras e geração de nome de arquivo pelo shell.

O equivalente, mas usando uma matriz 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"
    
por 19.06.2018 / 18:37
-1

A diferença é que escapar da cota \" a transforma em um caractere de string.

Portanto, o erro provavelmente está correto:

"/home/backuptest/dest/backuptest/20180619_134044"

Onde incluir as aspas fazem parte do nome é diferente de

/home/backuptest/dest/backuptest/20180619_134044

Qual é o que você quer A maneira recomendada de resolver isso é com variáveis $ {} por exemplo: %código% $ myvar=var $ echo "\"$myvar\"" "var"

Então, algo como "--link-dest" $ {BACKUP_ROOT} "/" $ {LAST_SNAPSHOT} "" Você deve chegar mais perto.

Para mais informações sobre isso: link e link

    
por 19.06.2018 / 18:12