Escapa aspas duplas na variável

4

Eu gostaria de colocar este comando em um arquivo para ser executado mais tarde:

ln -s "$xr"/ya.txt ~

Eu posso fazer isso com (1):

cat > zu.sh <<eof
ln -s "$xr"/ya.txt ~
eof

ou (2):

printf 'ln -s "%s"/ya.txt ~\n' "$xr" > zu.sh

ou (3):

echo "ln -s '$xr'/ya.txt ~" > zu.sh

ou (4):

printf 'ln -s %q/ya.txt ~\n' "$xr" > zu.sh

ou (5):

printf 'ln -s "%s"/ya.txt ~\n' "${xr//\"/\\"}"

no entanto, cada solução é problemática. se a variável em (1) ou (2) contiver um aspas duplas, eles falharão; se a variável em (3) contiver uma única citação, vai falhar. (4) é bom, mas não é definido pelo POSIX . (5) é bom mas é um Bashism . parece que a melhor opção seria usar (1) ou (2) e escape de aspas duplas na variável, mas isso pode ser feito de outra maneira?

    
por Steven Penny 06.02.2018 / 02:36

2 respostas

0

Usando a biblioteca Awk svnpenn / stdlib , testes com aspas, barra invertida, cifrão e backtick todos passam:

$ awklib 'BEGIN {printf "ln -s %s/ya.txt ~\n", sh_escape(ARGV[1])}' "2'2"
ln -s 2\'2/ya.txt ~

$ awklib 'BEGIN {printf "ln -s %s/ya.txt ~\n", sh_escape(ARGV[1])}' '2"2'
ln -s '2"2'/ya.txt ~

$ awklib 'BEGIN {printf "ln -s %s/ya.txt ~\n", sh_escape(ARGV[1])}' '2'
ln -s '2'/ya.txt ~

$ awklib 'BEGIN {printf "ln -s %s/ya.txt ~\n", sh_escape(ARGV[1])}' '2$2'
ln -s '2$2'/ya.txt ~

$ awklib 'BEGIN {printf "ln -s %s/ya.txt ~\n", sh_escape(ARGV[1])}' '2'2'
ln -s '2'2'/ya.txt ~

Disclaimer: eu escrevi esta biblioteca, mas posso excluir esta resposta se melhor opção existe.

    
por 06.02.2018 / 03:33
4

Acho que isso é seguro:

esc() {
    printf "%s\n" "$1" | sed -e "s/'/'\"'\"'/g" -e "1s/^/'/" -e "\$s/\$/'/"
}

aspas simples da string, para que qualquer $ , ' , \ e " na string de entrada não importam , e transforma qualquer caractere ' existente em '"'"' (ou seja, finalizar aspas simples, aspas duplas entre aspas simples e voltar a inserir cotação simples).

Era tentador usar $(...) substituição de comando lá, exceto que então ele irá comer qualquer nova linha na entrada. Em vez disso, as citações de abertura e fechamento são inseridas pelo segundo e terceiro scripts sed , em o começo da primeira linha e o fim da última linha. Quaisquer novas linhas incorporadas são deixadas em bruto, o que é bom.

A saída é adequada para copiar de volta para o shell, mesmo no caso mais patológico que eu possa inventar (usando Bash ANSI-C citando $'...' para criar a string de teste em primeiro lugar, mas não depois):

bash-4.4$ esc $'abc\ndef ghi\'jkl$mno'pqr\stu\\'vwx\n\n\n'
'abc
def ghi'"'"'jkl$mno'pqr\stu\'"'"'vwx


'
bash-4.4$ echo 'abc
> def ghi'"'"'jkl$mno'pqr\stu\'"'"'vwx
>
>
> '
abc
def ghi'jkl$mno'pqr\stu\'vwx



bash-4.4$ dash
$ echo 'abc
def ghi'"'"'jkl$mno'pqr\stu\'"'"'vwx


'> > > >
abc
def ghi'jkl$mno'pqr\stu\'vwx



$

É seguro colocar isso em uma variável xr=$(esc "$xr") e, em seguida, usá-la em substituição comum mais tarde, dentro do seu documento aqui ou em outro lugar.

    
por 06.02.2018 / 03:29