Как я могу избежать двойной кавычки внутри двойных кавычек?

287

Как я могу избежать двойных кавычек внутри двойной строки в Bash?

Например, в моем сценарии оболочки

#!/bin/bash

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

Я не могу получить ENCLOSED BY '\"'с двойной кавычкой, чтобы избежать правильно. Я не могу использовать одинарные кавычки для моей переменной, потому что я хочу использовать переменную $dbtable.

Шон Нгуен
источник
1
Также см. Mywiki.wooledge.org/BashFAQ/050
Чарльз Даффи
2
@kenorb Не похоже на дубликат этого вопроса ...
Марк
См. Также stackoverflow.com/questions/10067266/…
tripleee
@Daenyth Это не та команда, к которой вы ожидаете, что конечные пользователи будут иметь доступ. Сценарии массовой загрузки обычно запускаются на сервере доверенными пользователями (такими как системные администраторы или разработчики). Да, если конечные пользователи контролируют стоимость $dbtable, существует риск. Это было бы очень редко, поскольку конечные пользователи обычно не используют SSH для загрузки своих данных.
jpmc26

Ответы:

286

Используйте обратную косую черту:

echo "\""     # Prints one " character.
Питер
источник
9
Не работает. x=ls; if [ -f "$(which "\""$x"\"")" ]; then echo exists; else echo broken; fi;дает сломано, тогда как ... [ -f "$(which $x)" ]; ...или ... [ -f $(which "$x") ]; ...работает просто отлично. Проблемы могут возникнуть, когда либо $xрезультат, либо результат $(which "$x")с пробелом или другим специальным символом. Обходной путь - использовать переменную для хранения результата which, но действительно ли bash не в состоянии избежать кавычки или я что-то не так делаю?
Люк
Я пытаюсь использовать следующее grep -oh "\"\""$counter"\""\w*" как часть синтаксиса bash, где in $counterявляется переменной. это не нравится никаких мыслей
Джей Д
82

Простой пример экранирования кавычек в оболочке:

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

Это делается путем завершения уже открытого ( '), размещения экранированного ( \'), а затем открытия другого ( ').

В качестве альтернативы:

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

Это делается путем завершения уже открытой one ( '), размещения цитаты в другой quote ( "'") и последующего открытия другой ( ').

Дополнительные примеры: экранирование одинарных кавычек в одиночных кавычках

kenorb
источник
1
Я пробовал sh -c "echo" {"key": "value"} '"и даже sh -c" echo "{' '"' 'key' '"' ':' '"' value '' "' '}' "в попытке заключить слова ключ и значение в двойные кавычки, но в обоих случаях я получил {key: value}
Игорь Ягольницер
1
Это кажется излишне сложным для двойных кавычек: echo "abc\"abc"достаточно произвести, abc"abcкак в ответе Питера.
Divenex
2
В этом простом примере действительно, но в сложных случаях вложенных кавычек, это может быть необходимо, и пример @ kenorb помог мне понять, как справляться с этими случаями.
Просоитос
63

Я не знаю, почему эта старая проблема появилась сегодня в списках с тегами Bash, но на всякий случай для будущих исследователей, имейте в виду, что вы можете избежать побега, используя ASCII-коды символов, которые вам нужно отображать.

Пример:

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

\x22код ASCII (в шестнадцатеричном формате) для двойных и \x27одинарных кавычек. Точно так же вы можете повторить любой персонаж.

Я полагаю, что если мы попытаемся отразить вышеуказанную строку с помощью обратной косой черты, нам понадобится беспорядочное эхо с двумя строками обратной косой черты ... :)

Для присвоения переменной это эквивалентно:

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

Если переменная уже установлена ​​другой программой, вы все равно можете применять двойные / одинарные кавычки с помощью sed или аналогичных инструментов.

Пример:

 $ 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, потому что это решило проблему добавления переменной PS1 в ~ / .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
Это ответ! Я люблю тебя, сэр.
Мигель Рохас Кортес
28

Bash позволяет размещать строки рядом друг с другом, и в итоге они будут склеены.

Итак, это:

$ echo "Hello"', world!'

производит

Hello, world!

Хитрость заключается в чередовании одинарных и двойных кавычек по мере необходимости. К сожалению, это быстро становится очень грязным. Например:

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

производит

I like to use "double quotes" sometimes

В вашем примере я бы сделал это примерно так:

$ 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

который производит следующий вывод:

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

Трудно увидеть, что здесь происходит, но я могу аннотировать это с помощью кавычек Unicode. Следующее не будет работать в bash - это просто для иллюстрации:

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

Кавычки, подобные «'» в приведенном выше, будут интерпретироваться bash. Подобные кавычки " 'окажутся в результирующей переменной.

Если я приведу ту же обработку в предыдущем примере, это будет выглядеть так:

$ echo« I like to use» « "double quotes"» « sometimes»

жук
источник
4
Ох ... это некрасивые вещи.
Волшебная Урна Осьминога
17

Проверьте printf ...

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

Без использования printf

echo -e $mystr

Вывод: скажи "привет"

Использование printf

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

Вывод: скажи \ "привет \"

Дэнни Хонг
источник
2
Обратите внимание, что printfэкранируется больше символов, например ', (и)
David Pärsson
printf %qгенерирует строки, готовые для eval, а не отформатированные для echo -e.
Чарльз Даффи
2
Нет причин оборачивать printfих бесполезным использованиемecho . Оба ваших примера не соответствуют действительности. Правильное решение заключается в двойных кавычках переменной.
tripleee
15

Сохраните символ двойной кавычки как переменную:

DQT = '"'
echo "Двойные кавычки $ {dqt} X $ {dqt} внутри строки в двойных кавычках"

Вывод:

Двойные кавычки "X" внутри строки в двойных кавычках
12oclocker
источник
39
Баш действительно худший язык
Энди Рэй
@ 12oclocker, твой ответ надежен: D! особенно при использовании с командой «sed» это спасло мой день!
Артанис Зератул
11

Используйте $ "string".

В этом примере это было бы,

dbload = $ "загрузить данные локального файла \" 'gfpoint.csv' \ "в таблицу $ dbtable ПОЛЯ, ПРЕКРАЩЕННЫЕ ',' ЗАКРЫТЫМИ '\' 'ЛИНИями, ПРЕКРАЩЕНЫМИ \"' \ n '\ "IGNORE 1 LINES"

Примечание (со страницы руководства ):

Строка в двойных кавычках, перед которой стоит знак доллара ($ "string"), приведет к переводу строки в соответствии с текущей локалью. Если текущим языковым стандартом является C или POSIX, знак доллара игнорируется. Если строка переведена и заменена, замена заменяется двойными кавычками.

Триша Чаттерджи
источник
3
Хорошо, не знал этого.
Дэвид Киранс
-5

Добавить "\"перед двойной кавычкой, чтобы избежать его, вместо\

#! /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
источник
6
Downvote: Почему вы публикуете cshответ на bashвопрос? Два совершенно различны и несовместимы.
tripleee