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ì:

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