Почему содержимое JSON из heredoc не может быть разобрано?

11

У меня есть фрагмент JSON.

Следующее не работает:

VALUE=<<PERSON
{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "jim@gmail.com"  
}
PERSON
echo -n "$VALUE" | python -m json.tool

Результат:

Ни один объект JSON не может быть декодирован

Делать то же самое с jq, т.е.

echo -n "$VALUE" | jq '.'

Нет выхода.

Существует то же самое поведение для следующего:

VALUE=<<PERSON
'{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "jim@gmail.com"  
}'
PERSON
echo -n "$VALUE" | python -m json.tool

Отклик:

Ни один объект JSON не может быть декодирован

Но работает следующее:

VALUE='{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "jim@gmail.com"
}'
echo -n "$VALUE" | jq '.'
echo -n "$VALUE" | python -m json.tool
Джим
источник
5
Я не знаю, что делает bash, но после первых двух строк электронной почты есть запятая после запятой, но не на третьей, что делает первую пару незаконной JSON
Ник Т
@NickT ты должен ответить на этот вопрос, так как я думаю, что это именно та проблема.
rrauenza
Если это единственный ответ, его, вероятно, следует закрыть как «невозможно воспроизвести (опечатка)». Однако, похоже, что в ответе Кусы и Тердона упоминается, что перенаправление присваивания + полностью нарушено, поэтому вы получаете пустую строку, поэтому есть две проблемы, каждая из которых выдает ту же ошибку «Нет JSON ...». Хорошей практикой является деление пополам проблем путем проверки ваших предположений посередине: простое echo $VALUEбез ... | jqбудет информативным.
Ник Т
@NickT: Это была проблема копирования / вставки. Извините за путаницу
Джим

Ответы:

19
VALUE=<<PERSON
some data
PERSON

echo "$VALUE"

Нет вывода.

Документ здесь - это перенаправление , вы не можете перенаправить в переменную.

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

VALUE= <<PERSON
some data
PERSON

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

Обратите внимание, что

<<PERSON
some data
PERSON

действителен, как есть

<somefile

Просто нет команды, чей стандартный поток ввода может быть установлен для хранения данных, поэтому она просто теряется.

Это будет работать, хотя:

VALUE=$(cat <<PERSON
some data
PERSON
)

Здесь команда, которая получает здесь-документ cat, и копирует его в свой стандартный вывод. Это то, что присваивается переменной с помощью подстановки команд.

В вашем случае вы могли бы вместо этого использовать

python -m json.tool <<END_JSON
JSON data here
END_JSON

без дополнительных действий по сохранению данных в переменной.

Кусалананда
источник
2
Вы также можете просто сделать PERSON="с новой строкой и многострочными данными, а затем еще один "в конце.
R .. GitHub ОСТАНОВИТСЯ, ЧТОБЫ ЛЬДИТЬ
1
@R .. Да, но здесь документ позволяет обойти правила цитирования оболочки. Поэтому часто безопаснее использовать здесь документ вместо строки в кавычках для многострочных данных, особенно если данные содержат одинарные или двойные кавычки (или оба).
Кусалананда
2
@R .. Учитывая, что речь идет о JSON, может быть лучше использовать одинарные кавычки, чтобы не исключать двойные кавычки каждого имени свойства. PERSON=', Это если ОП не хочет интерполировать переменные позже.
JoL
(обратная косая черта) (новая строка), кажется, исчезает в документе здесь, даже если вы цитируете / экранируете слово-разделитель. Это может быть желательно, но есть ли способ отключить его?
Скотт
@ Scott Если этот вопрос ранее не задавался на этом сайте, это был бы отличный вопрос сам по себе.
Кусалананда
11

Потому что переменная не устанавливается вашим heredoc:

$ VALUE=<<PERSON  
> {    
>   "type": "account",  
>   "customer_id": "1234",  
>   "customer_email": "jim@gmail.com",  
> }  
> PERSON
$ echo "$VALUE" 

$

Если вы хотите использовать heredoc для присвоения значения переменной, вам нужно что-то вроде:

$ read -d '' -r VALUE <<PERSON  
{    
  "type": "account",  
  "customer_id": "1234",  
  "customer_email": "jim@gmail.com",  
}   
PERSON
Тердон
источник
1
Почему вы заключаете данные JSON в одинарные кавычки? Не похоже, что ОП хочет, чтобы они были частью его входной строки. Кроме того, +1 за сокращение популяции бездомных кошек. Как и в ответе Кусалананды, вы можете предложить << \PERSONзащиту от $s на входе и обратной косой черты на концах строк.
Скотт
@ Скотт, потому что я просто слепо скопировал текст из ОП. Спасибо
Тердон
3
Это правильный ответ. $(cat <<EOF ... EOF)странная конструкция: запустить subshell, а затем отправить heredoc в cat, чтобы он отправил его в STDOUT, а затем присвоить результат этого subshell переменной? Я хотел бы, чтобы люди думали о том, что они говорят о своих мыслительных процессах. Присвоение heredoc переменной с помощью readсравнения, является нормальным.
Богатое
Я бы не сказал, что $(cat << EOF... (данные) ... EOF )странно. Это неловко и запутанно, но так read -d … << EOF - особенно read -d '' << EOF . Я ценю ответ Тердона, потому что он использует только встроенные функции, а не программы. Но, что еще более важно, $(cat << EOF... (данные) ... EOF )завершается неудачей, если какие-либо строки заканчиваются \(обратная косая черта) - см. Комментарии под ответом Кусалананды .
Скотт
5

Это потому, что вы определили способ, которым вы определили Here-Doc для использования с JSON. Вы должны использовать его как

VALUE=$(cat <<EOF
{  
  "type": "account",  
  "customer_id": "1234",  
  "customer_email": "jim@gmail.com",  
}
EOF
)

и выполнение printf "$VALUE"должно сбросить JSON, как и ожидалось.

Inian
источник
3

Heredocs и переменные не смешиваются хорошо или, по крайней мере, не так. Вы также можете…

Передайте heredoc в качестве стандартного ввода приложения

python -m json.tool <<PERSON  
{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "jim@gmail.com",
}
PERSON

или…

Хранить многострочный текст в переменной оболочки

VALUE='{
  "type": "account",
  "customer_id": "1234",
  "customer_email": "jim@gmail.com",
}'

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

VALUE="{
  \"type\": \"account\",
  \"customer_id\": ${ID},
  \"customer_email\": \"${EMAIL}\",
}"

Затем вы можете использовать значение переменной позже.

echo -n "$VALUE" | python -m json.tool
Дэвид Фёрстер
источник