¿Cómo puedo escapar de una comilla doble dentro de comillas dobles?

286

¿Cómo puedo escapar de las comillas dobles dentro de una cadena doble en Bash?

Por ejemplo, en mi 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"

No puedo obtener la ENCLOSED BY '\"'comilla doble para escapar correctamente. No puedo usar comillas simples para mi variable, porque quiero usar variable $dbtable.

Sean Nguyen
fuente
1
También vea mywiki.wooledge.org/BashFAQ/050
Charles Duffy el
posible duplicado de comillas simples
kenorb
2
@kenorb no parece un duplicado de esa pregunta ...
Mark
@Daenyth Este no es el tipo de comando al que esperaría que los usuarios finales tuvieran acceso. Los scripts de carga masiva generalmente son ejecutados en el servidor por usuarios confiables (como administradores o desarrolladores del sistema). Sí, si los usuarios finales controlan el valor de $dbtable, existe un riesgo. Sin embargo, esto sería muy poco común, ya que los usuarios finales no suelen utilizar SSH en una máquina para cargar sus datos.
jpmc26

Respuestas:

285

Use una barra invertida:

echo "\""     # Prints one " character.
Peter
fuente
9
No funciona. x=ls; if [ -f "$(which "\""$x"\"")" ]; then echo exists; else echo broken; fi;da roto mientras que ... [ -f "$(which $x)" ]; ...o ... [ -f $(which "$x") ]; ...funciona bien. Surgirían problemas cuando cualquiera $xo el resultado de $(which "$x")dar algo con un espacio u otro carácter especial. Una solución alternativa está utilizando una variable para contener el resultado which, pero ¿bash es realmente incapaz de escapar de una cita o estoy haciendo algo mal?
Luc
Estoy tratando de usar lo siguiente grep -oh "\"\""$counter"\""\w*" como parte de una sintaxis bash donde in $counteres una variable. no le gusta ningún pensamiento
Jay D
82

Un ejemplo simple de comillas de escape en el shell:

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

Se realiza al terminar uno ya abierto ( '), colocar el que se escapó ( \') y luego abrir otro ( ').

Alternativamente:

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

Se realiza al terminar uno ya abierto ( '), colocar una cita en otra cita ( "'") y luego abrir otra ( ').

Más ejemplos: Escapar de comillas simples dentro de cadenas de comillas simples

kenorb
fuente
1
Intenté sh -c "echo '{" key ":" value "}'" e incluso sh -c "echo '{' '"' 'key' '"' ':' '"' 'value' '"' '}' "en un esfuerzo por encerrar las palabras clave y valor entre comillas dobles, pero en ambos casos obtuve {clave: valor}
Igor Yagolnitser
1
Esto parece innecesariamente complicado para las comillas dobles: echo "abc\"abc"es suficiente para producir abc"abccomo en la respuesta de Peter.
divenex
2
De hecho, en este ejemplo simple, pero en casos complejos de citas anidadas, puede ser necesario hacer esto y el ejemplo de @ kenorb me ayudó a descubrir cómo lidiar con esos casos.
prosoitos
63

No sé por qué este viejo problema apareció hoy en las listas etiquetadas de Bash, pero solo en el caso de futuros investigadores, tenga en cuenta que puede evitar escapar utilizando códigos ASCII de los caracteres que necesita hacer eco.

Ejemplo:

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

\x22es el código ASCII (en hexadecimal) para comillas dobles y \x27comillas simples. Del mismo modo, puedes hacer eco de cualquier personaje.

Supongo que si intentamos hacer eco de la cadena anterior con barras invertidas, necesitaremos un eco desordenado de dos filas con barra invertida ... :)

Para la asignación variable, este es el equivalente:

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

Si la variable ya está establecida por otro programa, aún puede aplicar comillas dobles / simples con sed o herramientas similares.

Ejemplo:

 $ 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
fuente
1
+1 porque resolvió el problema de agregar una variable PS1 a ~ / .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 es la respuesta! Te amo señor.
Miguel Rojas Cortés
28

Bash te permite colocar cadenas adyacentes, y terminarán pegadas.

Así que esto:

$ echo "Hello"', world!'

produce

Hello, world!

El truco consiste en alternar entre cadenas de comillas simples y dobles, según sea necesario. Desafortunadamente, rápidamente se vuelve muy desordenado. Por ejemplo:

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

produce

I like to use "double quotes" sometimes

En su ejemplo, lo haría algo como esto:

$ 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 produce el siguiente resultado:

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

Es difícil ver lo que está pasando aquí, pero puedo anotarlo usando comillas Unicode. Lo siguiente no funcionará en bash: es solo para ilustración:

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

Bash interpretará las citas como "''" en lo anterior. Las comillas como " 'terminarán en la variable resultante.

Si le doy el mismo tratamiento al ejemplo anterior, se ve así:

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

Escarabajo
fuente
44
Oof ... eso es algo feo.
Urna de pulpo mágico el
17

Echa un vistazo a printf ...

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

Sin usar printf

echo -e $mystr

Salida: di "hola"

Usando printf

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

Salida: di \ "hola \"

Danny Hong
fuente
2
Tenga en cuenta que también printfescapa más personajes, como ', (y)
David Pärsson
printf %qgenera cadenas listas para eval, no formateadas para echo -e.
Charles Duffy
2
No hay ninguna razón para envolver el printfcon un uso inútil deecho . Ambos ejemplos han roto las citas. La solución adecuada es comillas dobles de la variable.
tripleee
15

Almacene el carácter de comillas dobles como variable:

dqt = '"'
echo "Comillas dobles $ {dqt} X $ {dqt} dentro de una cadena entre comillas dobles"

Salida:

Comillas dobles "X" dentro de una cadena entre comillas dobles
12oclocker
fuente
39
Bash realmente es el peor idioma
Andy Ray
@ 12oclocker, su respuesta es infalible: D! ¡especialmente cuando se usa con el comando "sed" me salvó el día!
Artanis Zeratul
11

Haga uso de $ "cadena".

En este ejemplo, sería,

dbload = $ "cargar datos archivo local \" 'gfpoint.csv' \ "en la tabla $ dbtable CAMPOS TERMINADOS POR ',' CERRADO POR '\"' LÍNEAS TERMINADAS POR \ "'\ n' \" IGNORE 1 LINES "

Nota (de la página del manual ):

Una cadena con comillas dobles precedida por un signo de dólar ($ "cadena") hará que la cadena se traduzca de acuerdo con la configuración regional actual. Si el entorno local actual es C o POSIX, se ignora el signo de dólar. Si la cadena se traduce y reemplaza, el reemplazo se cita entre comillas.

Trisha Chatterjee
fuente
3
Bien, no lo sabía.
David Kierans
-5

Agregue "\"antes de la comilla doble para escapar, en lugar 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
fuente
66
Voto a favor: ¿Por qué publica una cshrespuesta a una bashpregunta? Los dos son completamente distintos e incompatibles.
tripleee