Usando pontos de exclamação na expansão do bash

1

No bash, eu construo um comando svn como uma string com opções de nome de usuário e senha adicionadas dinamicamente. Alguns usuários podem ter um ponto de exclamação na senha, o que pode resultar no seguinte:

svncmd='svn update --username=user --password password\! --non-interactive'
$($svncmd)

Mas isso expande meu ponto de exclamação, que não é o que eu quero. o que estou perdendo?

EDITAR:

Ah, acho que sei o que está acontecendo. Com este comando, posso apenas executá-lo como $ svncmd em vez de $ ($ svncmd). O que estava acontecendo foi bash estava reclamando sobre bash: At: comando não encontrado ... quando estava tentando executar "Na revisão xxxxx" como um comando. Opa.

    
por Kenneth Kam 29.05.2013 / 16:15

1 resposta

0

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[@]}"
    
por 31.05.2013 / 00:55

Tags