Como fazer o eco de uma string de escape

5

Como posso fazer o eco de uma string que contenha $ no Bourne Shell?

user@server:~$ cat test.sh 
#!/bin/sh
echo $1

user@server:~$ ./test.sh \$sad\$test
$sad$test

Eu quero que ele retorne uma versão com escape como esta:

user@server:~$ ./test.sh \$sad\$test
\$sad\$test

Eu tentei fazer truques com sed e awk, mas sem sorte. Qualquer orientação seria muito apreciada.

    
por Daniel 09.08.2011 / 04:05

4 respostas

0

No script:

echo "${1//$/\$}"

Esta é uma construção de substituição de cadeia simples no shell. A sintaxe é ${[VARIABLE_NAME]//[PATTERN]/[REPLACEMENT]} para uma substituição de cadeia literal global.

Não sei por que você gostaria de fazer isso. O script é, na verdade, apenas reportar a string que você enviou para ele; \$sad\$test avalia exatamente a mesma string que '$sad$test' , exceto que a última usa aspas simples para escapar da $ .

    
por 09.08.2011 / 04:40
7

Eu suponho que você deseja que a string seja mostrada como "shell quoted".

O comando embutido printf em ksh , bash e zsh todos entendem o %q especificador de formato. A saída real não é padronizada e pode variar dependendo da string de entrada (veja abaixo). Devido à variação na forma da saída, você pode não ser capaz de usar a saída de um shell com outro (especialmente se seu shell de destino for um shell menos rico em recursos como ash , traço , etc.).

zsh também tem suporte para gerar citações diretamente em expansões de parâmetros:

echo "${(q)1}"    # backslashes, with $'' for unprintable/invalid characters
echo "${(qq)1}"   # single quotes
echo "${(qqq)1}"  # double quotes
echo "${(qqqq)1}" # $'' quoting

Se você quiser “rolar o seu próprio”, a coisa mais fácil e confiável a fazer é criar o seu próprio orçamento. Um algoritmo simples segue:

  1. Altere as aspas simples para a sequência '\'' .
  2. Agrupe o resultado entre aspas simples.

Isso funciona para shells parecidos com o Bourne, porque a citação única é completamente literal 1 . Para representar uma aspa simples, você finaliza a atual cotação entre aspas simples, fornece uma aspa simples com escape de barra invertida e retorna uma única citando o restante da string. O algoritmo acima é ineficiente quando se lida com execuções de aspas simples e consecutivas e aspas simples no início e no final da string, mas é muito confiável e simples de implementar.

1 A aspas simples em outros idiomas geralmente não são completamente literais (no mínimo, elas geralmente permitem que algumas barras invertidas limitadas escapem). É por isso que é extremamente importante que você conheça todas as regras de cotação para a forma de cotação que você estará gerando (ou seja, em que idioma / contexto o texto citado será usado).

Aqui estão alguns exemplos de printf %q nos shells que eu instalei localmente:

for s in /bin/ksh {,/opt/local}/bin/bash {,/opt/local}/bin/zsh
do
  "$s" --version | head -1
  "$s" -c 'printf "%q\n" "$@"' - \$sad\$test \'mixed\ quotes\" back\'tick
  echo
done

Saída:

  version         sh (AT&T Research) 1993-12-28 s+
'$sad$test'
$'\'mixed quotes"'
'back'tick'

GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin10.0)
\$sad\$test
\'mixed\ quotes\"
back\'tick

GNU bash, version 4.2.10(2)-release (i386-apple-darwin10.7.0)
\$sad\$test
\'mixed\ quotes\"
back\'tick

zsh 4.3.9 (i386-apple-darwin10.0)
\$sad\$test
\'mixed\ quotes\"
back\'tick

zsh 4.3.12 (i386-apple-darwin10.7.0)
\$sad\$test
\'mixed\ quotes\"
back\'tick

Vemos que ksh parece "gostar" de citar com aspas simples e usa a forma $'' em alguns casos. Os outros shells parecem usar principalmente escapes de barra invertida (embora eles também usem $'' se alguns caracteres estiverem presentes).

    
por 09.08.2011 / 07:39
1

Coloque aspas simples em torno de \$sad\$test :

$ echo $SHELL
/bin/bash
$ ./test.sh '\$sad\$test'
\$sad\$test
    
por 09.08.2011 / 04:50
1

Ao fazer test.sh \$sad\$test , o script test.sh recebe $sad$test como seu parâmetro, não \$sad\$test . O motivo para isso é o shell que substitui \$ por $ antes de chamar test.sh . Se você quiser que seu script receba \$sad\$test , faça test.sh '\$sad\$test' ou test.sh "\\$sad\\$test" .

Tente convencer-se:

function cat1stpar() {
cat << EOF
$1
EOF
}
cat1stpar \$sad\$test
cat1stpar '\$sad\$test'
cat1stpar "\\$sad\\$test"

Além disso, no caso geral, usar echo $1 é perigoso. Se você fizer:

./test.sh "aaa bbb"
./test.sh "aaa    bbb"

A saída será:

aaa bbb
aaa bbb

e não:

aaa bbb
aaa    bbb

Se você quiser a segunda saída, deve pelo menos fazer echo "$1" , o que fará com que echo receba um único parâmetro, não tanto quanto palavras em $ 1. Para uma discussão completa de palavras, veja a variável IFS no shell man.

Também é dito que fazer printf "%s\n" "$1" é mais seguro que echo "$1" porque echo altera alguns caracteres antes da impressão, mas ainda não entendi completamente.

Editar:

Sobre echo alterando caracteres, eu apenas entendi. Experimente:

echo "-n"
printf "%s\n" "-n"
./test.sh "-n"
cat1stpar "-n"
    
por 09.08.2011 / 12:39

Tags