Jak mogę uniknąć podwójnego cytatu w podwójnych cudzysłowach?

286

Jak mogę uniknąć podwójnych cudzysłowów w podwójnym ciągu w Bash?

Na przykład w moim skrypcie powłoki

#!/bin/bash

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

Nie mogę uzyskać ENCLOSED BY '\"'podwójnego cytatu, aby poprawnie uciec. Nie mogę używać pojedynczych cudzysłowów dla mojej zmiennej, ponieważ chcę używać zmiennej $dbtable.

Sean Nguyen
źródło
1
Zobacz także mywiki.wooledge.org/BashFAQ/050
Charles Duffy
2
@kenorb Nie wygląda jak duplikat tego pytania ...
Mark
@Daenyth Nie jest to polecenie, do którego użytkownicy końcowi mieliby mieć dostęp. Skrypty ładowania zbiorczego są zwykle uruchamiane na serwerze przez zaufanych użytkowników (takich jak administratorzy systemu lub programiści). Tak, jeśli użytkownicy końcowi kontrolują wartość $dbtable, istnieje ryzyko. Byłoby to jednak bardzo rzadkie, ponieważ użytkownicy końcowi zazwyczaj nie używają SSH do komputera w celu załadowania swoich danych.
jpmc26

Odpowiedzi:

285

Użyj ukośnika odwrotnego:

echo "\""     # Prints one " character.
Piotr
źródło
9
Nie działa. x=ls; if [ -f "$(which "\""$x"\"")" ]; then echo exists; else echo broken; fi;daje uszkodzony podczas ... [ -f "$(which $x)" ]; ...lub ... [ -f $(which "$x") ]; ...praca dobrze. Problemy pojawiałyby się, gdy którykolwiek $xlub wynik $(which "$x")dawałby coś ze spacją lub innym znakiem specjalnym. Obejście polega na użyciu zmiennej do przechowywania wyniku which, ale czy bash naprawdę nie jest w stanie uciec od cytatu, czy robię coś źle?
Luc
Próbuję użyć następujących elementów grep -oh "\"\""$counter"\""\w*" jako części składni bash, gdzie in $counterjest zmienną. nie podoba mi się żadna myśl
Jay D
82

Prosty przykład ucieczki cytatów w powłoce:

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

Odbywa się to poprzez ukończenie już otwartej ( '), umieszczenie ucieczki ( \'), a następnie otwarcie kolejnej ( ').

Alternatywnie:

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

Odbywa się to poprzez ukończenie już otwartego jednego ( '), umieszczenie cytatu w innym cytacie ( "'"), a następnie otwarcie kolejnego ( ').

Więcej przykładów: unikanie pojedynczych cudzysłowów w ciągach pojedynczych cudzysłowów

kenorb
źródło
1
Próbowałem sh-c „echo” {„klucz”: „wartość”} ””, a nawet sh -c „echo” {„” „” klucz „” „”: „” „” „” „” „}” ”, aby zawrzeć słowa klucz i wartość w podwójnych cudzysłowach, ale w obu przypadkach otrzymałem {klucz: wartość}
Igor Yagolnitser
1
Wydaje się to niepotrzebnie skomplikowane w przypadku podwójnych cytatów: echo "abc\"abc"wystarczy, aby uzyskać abc"abcjak w odpowiedzi Piotra.
divenex,
2
W tym prostym przykładzie rzeczywiście, ale w skomplikowanych przypadkach zagnieżdżonych cudzysłowów, może to być konieczne, a przykład @ kenorb pomógł mi wymyślić, jak sobie z nimi poradzić.
prosoitos
63

Nie wiem, dlaczego ten stary problem pojawił się dzisiaj na listach oznaczonych Bash, ale na wszelki wypadek dla przyszłych badaczy, pamiętaj, że możesz uniknąć ucieczki, używając kodów ASCII znaków, które musisz echo.

Przykład:

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

\x22jest kodem ASCII (szesnastkowym) dla podwójnych cudzysłowów i \x27pojedynczych cudzysłowów. Podobnie możesz powtórzyć dowolny znak.

Przypuszczam, że jeśli spróbujemy powtórzyć powyższy ciąg za pomocą ukośników odwrotnych, będziemy potrzebować niechlujnego echa z dwoma odwróconymi ukośnikami ...

W przypadku przypisania zmiennych jest to odpowiednik:

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

Jeśli zmienna jest już ustawiona przez inny program, nadal możesz stosować podwójne / pojedyncze cudzysłowy za pomocą sed lub podobnych narzędzi.

Przykład:

 $ 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
źródło
1
+1, ponieważ rozwiązał problem dodawania zmiennej PS1 do ~ / .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 18.04.17
1
To jest odpowiedź! Kocham cię Sir.
Miguel Rojas Cortés
28

Bash pozwala ci umieszczać łańcuchy obok siebie, a po prostu zostaną sklejone.

Więc to:

$ echo "Hello"', world!'

produkuje

Hello, world!

Sztuczka polega na przełączaniu między ciągami pojedynczymi i podwójnymi w razie potrzeby. Niestety szybko robi się bardzo bałagan. Na przykład:

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

produkuje

I like to use "double quotes" sometimes

W twoim przykładzie zrobiłbym coś takiego:

$ 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

co daje następujące dane wyjściowe:

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

Trudno zobaczyć, co się tutaj dzieje, ale mogę to opatrzyć adnotacjami, używając cytatów Unicode. Poniższe nie działa w bash - to tylko dla ilustracji:

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

Cytaty takie jak „” ”powyżej zostaną zinterpretowane przez bash. Cytaty jak" ' zakończą się w wynikowej zmiennej.

Jeśli podam to samo traktowanie we wcześniejszym przykładzie, wygląda to tak:

$ echoI like to use"double quotes"sometimes

Chrząszcz
źródło
4
Ooo ... to brzydkie rzeczy.
Magic Octopus Urn
17

Sprawdź printf ...

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

Bez użycia printf

echo -e $mystr

Wyjście: powiedz „cześć”

Korzystanie z printf

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

Wyjście: powiedz „cześć”

Danny Hong
źródło
2
Zauważ, że printfwymyka się więcej znaków, jak również, takie jak ', (i)
David Pärsson
printf %qgeneruje ciągi gotowe eval, nie sformatowane dla echo -e.
Charles Duffy
2
Nie ma powodu, aby owinąć printfz bezużytecznego wykorzystaniaecho . Oba twoje przykłady mają zepsute cytaty. Poprawną poprawką jest podwójne cytowanie zmiennej.
tripleee
15

Zapisz znak podwójnego cudzysłowu jako zmienną:

dqt = '”
echo „Podwójne cudzysłowy $ {dqt} X $ {dqt} w ciągu podwójnego cudzysłowu”

Wynik:

Podwójne cudzysłowy „X” wewnątrz ciągu podwójnego cudzysłowu
12clocker
źródło
39
Bash to naprawdę najgorszy język
Andy Ray
@ 12oclocker, twoja odpowiedź jest niezawodna: D! szczególnie przy użyciu polecenia „sed” uratowało mi to dzień!
Artanis Zeratul,
11

Skorzystaj z $ „string”.

W tym przykładzie byłoby to

dbload = $ "ładuj lokalny plik danych \" 'gfpoint.csv' \ "do tabeli $ dbtable POLA ZAKOŃCZONE PRZEZ ',' OBEJMOWANE PRZEZ '\' 'LINIE ZAKOŃCZONE PRZEZ \"' \ n '\ "IGNORE 1 LINES"

Uwaga (od strony man ):

Ciąg cudzysłowu poprzedzony znakiem dolara ($ „ciąg”) spowoduje, że zostanie on przetłumaczony zgodnie z bieżącymi ustawieniami narodowymi. Jeśli bieżące ustawienia narodowe to C lub POSIX, znak dolara jest ignorowany. Jeśli ciąg zostanie przetłumaczony i zastąpiony, zamiennik jest cytowany podwójnie.

Trisha Chatterjee
źródło
3
Fajnie, nie wiedziałem tego.
David Kierans,
-5

Dodaj "\"przed podwójnym cytatem, aby go uniknąć, zamiast\

#! /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
źródło
6
Downvote: Dlaczego publikujesz cshodpowiedź nabash pytanie? Oba są całkowicie różne i niezgodne.
tripleee