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.