Armazenar um comando em uma variável e, em seguida, executá-lo conforme pretendido é complicado, devido à ordem em que o shell analisa a linha de comando. Ele analisa (e aplica e remove) aspas e escapa, em seguida, substitui as variáveis, em seguida, faz a divisão de palavras e a expansão de caracteres curinga, mas não volta e interpreta as saídas e aspas nos valores das variáveis substituídas. Como resultado, se o comando armazenado em uma variável tiver aspas ou escapa, elas não terão o efeito pretendido. Suponha, por exemplo, que a senha do usuário fosse 'foo * bar' se você configurasse o comando para svncmd='svn update --username=user --password foo * bar --non-interactive'
e então executasse como $svncmd
, ele pegaria 'foo' como senha e então obteria uma lista de arquivos no diretório atual seguido por 'bar' como argumentos separados. Por outro lado, se você guardasse o comando como svncmd='svn update --username=user --password "foo * bar" --non-interactive'
, tomaria "foo" como senha, depois a lista de arquivos seguida por "bar" '...
A melhor maneira de lidar com isso no bash é geralmente armazenar o comando como uma matriz (em que cada "palavra" do comando é um elemento da matriz), e invocá-lo como "${svncmd[@]}"
- o [@]
torna trate cada elemento como uma palavra de comando, e as aspas duplas impedem qualquer análise adicional dos elementos da matriz depois de serem substituídos. Assim, você criaria o comando da seguinte forma:
svncmd=(svn update --username=user)
if [ $pwdfromvar ]; then
svncmd+=(--password "$userpw") # Double-quotes allow variable substitution, prevent parsing of the substituted value
elif [ $defaultpw ]; then
svncmd+=(--password 'password!') # Single-quotes prevent the ! from being interpreted
else
IFS= read -rs -p "Password:" # Raw read without echo
echo
svncmd+=(--password "$REPLY")
fi
svncmd+=(--non-interactive)
"${svncmd[@]}"