Como escapar de aspas duplas dentro de aspas duplas?

286

Como escapar aspas duplas dentro de uma sequência dupla no Bash?

Por exemplo, no meu script de shell

#!/bin/bash

dbload="load data local infile \"'gfpoint.csv'\" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY \"'\n'\" IGNORE 1 LINES"

Não consigo fazer ENCLOSED BY '\"'com que as aspas duplas escapem corretamente. Não posso usar aspas simples para minha variável, porque quero usar a variável $dbtable.

Sean Nguyen
fonte
1
Veja também mywiki.wooledge.org/BashFAQ/050
Charles Duffy
2
@kenorb não se parece com uma duplicata dessa pergunta ...
Mark
Veja também stackoverflow.com/questions/10067266/…
tripleee 16/17
@ Daenyth Este não é o tipo de comando que você espera que os usuários finais tenham acesso. Os scripts de carregamento em massa geralmente são executados no servidor por usuários confiáveis ​​(como administradores ou desenvolvedores do sistema). Sim, se os usuários finais controlam o valor de $dbtable, há um risco. Isso seria muito incomum, no entanto, como os usuários finais normalmente não fazem SSH em uma máquina para carregar seus dados.
precisa

Respostas:

285

Use uma barra invertida:

echo "\""     # Prints one " character.
Peter
fonte
9
Não está funcionando. x=ls; if [ -f "$(which "\""$x"\"")" ]; then echo exists; else echo broken; fi;dá quebrado enquanto ... [ -f "$(which $x)" ]; ...ou ... [ -f $(which "$x") ]; ...funciona muito bem. Surgiriam problemas quando um $xou o resultado de desse $(which "$x")algo com um espaço ou outro caractere especial. Uma solução alternativa está usando uma variável para conter o resultado which, mas o bash é realmente incapaz de escapar de uma cotação ou estou fazendo algo errado?
Luc
Estou tentando usar o seguinte grep -oh "\"\""$counter"\""\w*" como parte de uma sintaxe bash em que in $counteré uma variável. ele não gosta de nenhum pensamento
Jay D
82

Um exemplo simples de escape de aspas no shell:

$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc

Isso é feito finalizando um já aberto ( '), colocando o escapado ( \') e abrindo outro ( ').

Alternativamente:

$ echo 'abc'"'"'abc'
abc'abc
$ echo "abc"'"'"abc"
abc"abc

Isso é feito terminando já aberto um ( '), colocando uma cotação em outra cotação ( "'") e depois abrindo outra ( ').

Mais exemplos: Escapando aspas simples em strings entre aspas simples

kenorb
fonte
1
Tentei sh -c "echo '{" key ":" value "}'" e até mesmo sh -c "echo '{' '"' 'key' '"' ':' '"' 'value' '"' '}' "em um esforço para colocar as palavras chave e valor entre aspas duplas, mas em ambos os casos eu recebi {key: value}
Igor Yagolnitser
1
Isso parece desnecessariamente complicado para aspas duplas: echo "abc\"abc"é suficiente para produzir abc"abccomo na resposta de Peter.
divenex
2
De fato, neste exemplo simples, mas em casos complexos de aspas aninhadas, pode ser necessário fazer isso e o exemplo do @ kenorb me ajudou a descobrir como lidar com esses casos.
Prosoitos 3/05/19
63

Não sei por que esse problema antigo apareceu hoje nas listagens marcadas com Bash, mas, no caso de futuros pesquisadores, lembre-se de que você pode evitar escapar usando códigos ASCII dos caracteres que você precisa ecoar.

Exemplo:

 echo -e "This is \x22\x27\x22\x27\x22text\x22\x27\x22\x27\x22"
 This is "'"'"text"'"'"

\x22é o código ASCII (em hex) para aspas duplas e \x27aspas simples. Da mesma forma, você pode repetir qualquer personagem.

Suponho que, se tentarmos fazer eco da string acima com barras invertidas, precisaremos de um eco bagunçado de duas linhas com barra invertida ... :)

Para atribuição de variável, isso é equivalente:

 $ a=$'This is \x22text\x22'
 $ echo "$a"
 This is "text"

Se a variável já estiver definida por outro programa, você ainda poderá aplicar aspas duplas / simples com ferramentas sed ou similares.

Exemplo:

 $ b="Just another text here"
 $ echo "$b"
 Just another text here
 $ sed 's/text/"'\0'"/' <<<"$b" #\0 is a special sed operator
 Just another "0" here #this is not what i wanted to be
 $ sed 's/text/\x22\x27\0\x27\x22/' <<<"$b"
 Just another "'text'" here #now we are talking. You would normally need a dozen of backslashes to achieve the same result in the normal way.
George Vasiliou
fonte
1
1, pois resolvido um problema de adicionar uma variável PS1 para ~ / .profile echo 'export PS1='\[\033[00;31m\]${?##0}$([ $? -ne 0 ] && echo \x22 \x22)\[\033[00;32m\]\u\[\033[00m\]@\[\033[00;36m\]\h\[\033[00m\][\[\033[01;33m\]\d \t\[\033[00m\]] \[\033[01;34m\]\w\n\[\033[00m\]$( [ ${EUID} -ne 0 ] && echo \x22$\x22 || echo \x22#\x22 ) '' >> ~/.profile
Yassine ElBadaoui
1
Esta é a resposta! Eu te amo, senhor.
Miguel Rojas Cortés
28

O Bash permite que você coloque seqüências de caracteres adjacentes, e elas acabam sendo coladas.

Então, é isso:

$ echo "Hello"', world!'

produz

Hello, world!

O truque é alternar entre cadeias simples e duplas, conforme necessário. Infelizmente, rapidamente fica muito confuso. Por exemplo:

$ echo "I like to use" '"double quotes"' "sometimes"

produz

I like to use "double quotes" sometimes

No seu exemplo, eu faria algo assim:

$ dbtable=example
$ dbload='load data local infile "'"'gfpoint.csv'"'" into '"table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"'"'"' LINES "'TERMINATED BY "'"'\n'"'" IGNORE 1 LINES'
$ echo $dbload

que produz a seguinte saída:

load data local infile "'gfpoint.csv'" into table example FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "'\n'" IGNORE 1 LINES

É difícil ver o que está acontecendo aqui, mas posso anotá-lo usando aspas Unicode. O seguinte não funciona no bash - é apenas para ilustração:

dbload=' load data local infile "' 'gfpoint.csv'' " into' table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '' "' “ ' LINES” ' TERMINATED BY "' '\n'' " IGNORE 1 LINES' ' ' ' ' ' '

As aspas como "''" acima serão interpretadas por bash. As aspas como " 'vão acabar na variável resultante.

Se eu der o mesmo tratamento ao exemplo anterior, ele ficará assim:

$ echoI like to use' "double quotes"' sometimes

Besouro
fonte
4
Oof ... isso é uma coisa feia.
Magic Octopus Urn
17

Confira printf ...

#!/bin/bash
mystr="say \"hi\""

Sem usar printf

echo -e $mystr

Saída: diga "oi"

Usando printf

echo -e $(printf '%q' $mystr)

Saída: diga \ "oi \"

Danny Hong
fonte
2
Note-se que printfescapa mais caracteres, bem como, tais como ', (e)
David Pärsson
printf %qgera seqüências de caracteres prontas para eval, não formatadas para echo -e.
Charles Duffy #
2
Não há razão para encerrar o arquivo printfcom um uso inútil deecho . Ambos os seus exemplos estão com citações quebradas. A correção adequada é colocar aspas duplas na variável.
tripleee
15

Armazene o caractere de aspas duplas como variável:

dqt = '"'
echo "aspas duplas $ {dqt} X $ {dqt} dentro de uma sequência de aspas duplas"

Resultado:

Aspas duplas "X" dentro de uma cadeia de caracteres entre aspas duplas
12oclocker
fonte
39
Bash é realmente a pior linguagem #
Andy Ray
@ 12oclocker, sua resposta é infalível: D! especialmente ao usar com o comando "sed", ele salvou meu dia!
Artanis Zeratul
11

Faça uso de $ "string".

Neste exemplo, seria,

dbload = $ "carrega o infile local de dados \" 'gfpoint.csv' \ "na tabela $ dbtable CAMPOS TERMINADOS POR ',' INCLOSED BY '\"' LINHAS TERMINADAS POR \ "'\ n' \" IGNORAR 1 LINHAS "

Nota (na página de manual ):

Uma sequência de aspas duplas precedida por um cifrão ($ "string") fará com que a string seja traduzida de acordo com o código de idioma atual. Se o código do idioma atual for C ou POSIX, o cifrão será ignorado. Se a sequência for traduzida e substituída, a substituição será citada duas vezes.

Trisha Chatterjee
fonte
3
Bom, não sabia disso.
David Kierans
-5

Adicione "\"antes de aspas duplas para escapar, em vez de\

#! /bin/csh -f

set dbtable = balabala

set dbload = "load data local infile "\""'gfpoint.csv'"\"" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"\""' LINES TERMINATED BY "\""'\n'"\"" IGNORE 1 LINES"

echo $dbload
# load data local infile "'gfpoint.csv'" into table balabala FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "''" IGNORE 1 LINES
Shilv
fonte
6
Downvote: Por que você está postando uma cshresposta para uma bashpergunta? Os dois são completamente distintos e incompatíveis.
tripleee