Come posso evitare una virgoletta doppia tra virgolette doppie?


287

Come posso evitare doppie virgolette all'interno di una doppia stringa in Bash?

Ad esempio, nel mio script di 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"

Non riesco a far ENCLOSED BY '\"'uscire correttamente la doppia virgoletta. Non posso usare virgolette singole per la mia variabile, perché voglio usare la variabile $dbtable.




2
@kenorb Non sembra un duplicato di quella domanda ...
— Segna il


@Daenyth Questo non è il tipo di comando a cui ti aspetteresti che gli utenti finali abbiano accesso. Gli script di caricamento di massa vengono generalmente eseguiti sul server da utenti fidati (come amministratori di sistema o sviluppatori). Sì, se gli utenti finali controllano il valore di $dbtable, c'è un rischio. Ciò sarebbe molto raro, tuttavia, poiché gli utenti finali in genere non SSH in una macchina per caricare i propri dati.
— jpmc26

Risposte:


285

Usa una barra rovesciata:

echo "\""     # Prints one " character.

9
Non funziona. x=ls; if [ -f "$(which "\""$x"\"")" ]; then echo exists; else echo broken; fi;dà rotto mentre ... [ -f "$(which $x)" ]; ...o ... [ -f $(which "$x") ]; ...funziona bene. Problemi sorgerebbero quando uno $xo il risultato di $(which "$x")dare qualcosa con uno spazio o un altro carattere speciale. Una soluzione alternativa sta usando una variabile per contenere il risultato which, ma bash è davvero incapace di sfuggire a un preventivo o sto facendo qualcosa di sbagliato?
— Luc,

Sto cercando di utilizzare quanto segue grep -oh "\"\""$counter"\""\w*" come parte di una sintassi bash in cui $counterè una variabile. non gli piace alcun pensiero
— Jay D

82

Un semplice esempio di virgolette di escape nella shell:

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

Viene fatto finendo uno già aperto ( '), posizionando quello evaso (\' ) e quindi aprendo un altro ( ').

In alternativa:

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

Viene fatto finendo uno ( ') già aperto , inserendo una citazione in un'altra ("'" ) e quindi aprendo un'altra ( ').

Altri esempi: escape di virgolette singole all'interno di stringhe tra virgolette singole


1
Ho provato sh -c "echo '{" key ":" value "}'" e persino sh -c "echo '{' '"' 'key' '"' ':' '"' '' value '' "' '}' "nel tentativo di racchiudere le parole chiave e valore tra virgolette doppie, ma in entrambi i casi ho ricevuto {chiave: valore}
— Igor Yagolnitser il

1
Questo sembra inutilmente complicato per le doppie virgolette: echo "abc\"abc"è sufficiente produrre abc"abccome nella risposta di Peter.
— divenex,

2
In questo semplice esempio, in effetti, ma in casi complessi di citazioni nidificate, può essere necessario fare questo e l'esempio di @ kenorb mi ha aiutato a capire come affrontare quei casi.
— prosoitos,

63

Non so perché questo vecchio problema sia apparso oggi negli elenchi con tag di Bash, ma nel caso dei futuri ricercatori, tieni presente che puoi evitare di scappare usando i codici ASCII dei caratteri che devi eco.

Esempio:

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

\x22è il codice ASCII (in esadecimale) per virgolette doppie e \x27virgolette singole. Allo stesso modo puoi fare eco a qualsiasi personaggio.

Suppongo che se proviamo a fare eco alla stringa sopra con barre rovesciate, avremo bisogno di un'eco disordinata a due righe rovesciata ... :)

Per assegnazione variabile questo è l'equivalente:

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

Se la variabile è già impostata da un altro programma, è comunque possibile applicare virgolette doppie / singole con strumenti sed o simili.

Esempio:

 $ 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.

1
+1 perché risolto il problema di aggiungere una variabile 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
Questa è la risposta! Ti voglio bene signore.
— Miguel Rojas Cortés,

28

Bash ti consente di posizionare le stringhe in modo adiacente e finiranno per essere incollate insieme.

Così questo:

$ echo "Hello"', world!'

produce

Hello, world!

Il trucco è alternare stringhe singole e doppie tra virgolette come richiesto. Sfortunatamente, diventa rapidamente molto disordinato. Per esempio:

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

produce

I like to use "double quotes" sometimes

Nel tuo esempio, lo farei in questo modo:

$ 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

che produce il seguente output:

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

È difficile vedere cosa sta succedendo qui, ma posso annotarlo usando le virgolette Unicode. Quanto segue non funzionerà in bash - è solo a scopo illustrativo:

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

Le virgolette come "" "di cui sopra saranno interpretate da bash. Le virgolette come " 'finiranno nella variabile risultante.

Se do lo stesso trattamento all'esempio precedente, si presenta così:

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


4
Oof ... sono cose brutte.
— Magic Octopus Urn

17

Dai un'occhiata a printf ...

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

Senza usare printf

echo -e $mystr

Output: dire "ciao"

Utilizzando printf

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

Output: dire \ "ciao \"


2
Nota che printfsfugge anche a più personaggi, come ', (e)
— David Pärsson,

printf %qgenera stringhe pronte per eval, non formattate per echo -e.
— Charles Duffy,

2
Non c'è motivo di concludere printfcon un uso inutile diecho . Entrambi i tuoi esempi hanno rotto le citazioni. La correzione corretta consiste nel virgolette doppie per la variabile.
— Tripleee

15

Memorizza il carattere di virgoletta doppia come variabile:

DQT = '"'
echo "Virgolette doppie {{dqt} X $ {dqt} all'interno di una stringa tra virgolette doppie"

Produzione:

Virgolette doppie "X" all'interno di una stringa tra virgolette doppie

39
Bash è davvero la lingua peggiore
— Andy Ray,

@ 12oclocker, la tua risposta è infallibile: D! specialmente usando il comando "sed" mi ha salvato la giornata!
— Artanis Zeratul,

11

Usa $ "stringa".

In questo esempio, sarebbe,

dbload = $ "carica dati locali" \ "'gfpoint.csv' \" nella tabella $ dbtable CAMPI TERMINATI DA ',' RILASCIATI DA '\ "' LINEE TERMINATE DA \" '\ n' \ "IGNORE 1 LINES"

Nota (dalla pagina man ):

Una stringa tra virgolette preceduta da un simbolo di dollaro ($ "stringa") farà sì che la stringa venga tradotta in base alle impostazioni internazionali correnti. Se la locale corrente è C o POSIX, il simbolo del dollaro viene ignorato. Se la stringa viene tradotta e sostituita, la sostituzione viene racchiusa tra virgolette.


3
Bello, non lo sapevo.
— David Kierans,

-5

Aggiungi "\"prima della doppia citazione per evitarlo, invece di\

#! /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

6
Downvote: Perché pubblichi una cshrisposta a una bashdomanda? I due sono completamente distinti e incompatibili.
— Tripleee
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.