bash script - невозможно установить переменную с двойными кавычками в значении

Нужна помощь в исправлении этого скрипта bash, чтобы установить переменную со значением, включающим двойные кавычки. Почему-то я неправильно определяю это как мои ценности foo а также bar при необходимости не заключаются в двойные кавычки.

Мой сценарий до сих пор:

#!/usr/local/bin/bash
set -e
set -x

host='127.0.0.1'
db='mydev'
_account="foo"
_profile="bar"
_version=$1
_mongo=$(which mongo);

exp="db.profile_versions_20170420.find({account:${_account}, profile:${_profile}, version:${_version}}).pretty();";
${_mongo} ${host}/${db} --eval "$exp"

set +x

Вывод показывает:

+ host=127.0.0.1
+ db=mydev
+ _account=foo
+ _profile=bar
+ _version=201704112004
++ which mongo
+ _mongo=/usr/local/bin/mongo
+ exp='db.profile_versions_20170420.find({account:foo, profile:bar, version:201704112004}).pretty();'
+ /usr/local/bin/mongo 127.0.0.1/mydev --eval 'db.profile_versions_20170420.find({account:foo, profile:bar, version:201704112004}).pretty();'
MongoDB shell version: 3.2.4
connecting to: 127.0.0.1/mydev
2017-04-22T15:32:55.012-0700 E QUERY    [thread1] ReferenceError: foo is not defined :
@(shell eval):1:36

Что мне нужно account:"foo", profile:"bar" быть заключенным в двойные кавычки.

4 ответа

Решение

В bash (и других оболочках POSIX) следующие 2 состояния эквивалентны:

_account=foo
_account="foo"

Что вы хотите сделать, это сохранить цитаты, поэтому вы можете сделать следующее:

_account='"foo"'

Поскольку часть того, что вы делаете здесь, формирует JSON, рассмотрите возможность использования jq - что гарантирует его правильную форму, независимо от того, какие ценности.

host='127.0.0.1'
db='mydev'
_account="foo"
_profile="bar"
_version=$1

json=$(jq -n --arg account "$_account" --arg profile "$_profile" --arg version "$_version" \
  '{$account, $profile, version: $version | tonumber}')

exp="db.profile_versions_20170420.find($json).pretty();"
mongo "${host}/${db}" --eval "$exp"

Это делает jq отвечает за добавление буквенных кавычек, где это уместно, и избегает попыток инъекционных атак (например, через версию, переданную $1 содержащий что-то вроде 1, "other_argument": "malicious_value"), заменив любой буквальный " в строке с \"; буквальный перевод строки с \nи т. д. - или с | tonumber преобразование, терпящее неудачу сразу с любым нечисловым значением.


Обратите внимание, что для некоторых из приведенных выше синтаксисов требуется jq 1.5 - если у вас версия 1.4 или более ранняя, вы захотите написать {account: $account, profile: $profile} вместо возможности писать {$account, $profile} с именами ключей, выведенными из имен переменных.

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

$ foo="acount:\"foo\"" sh -c 'echo $foo'
  acount:"foo"

Мне нужно было заключить что-то уже в переменную и вставить это в переменную. Расширяя ответ Роберта Симана , я обнаружил, что это сработало:

      VAR='"'$1'"'

(одинарная кавычка, двойная кавычка, одинарная кавычка,
переменная,
одинарная кавычка, двойная кавычка, одинарная кавычка)

Другие вопросы по тегам