Чому вміст 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
Я не знаю, чим займається баш, але після рядка електронної пошти у ваших перших двох є кінцева кома, але не на третій, що зробить першу пару незаконною 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 Якщо цього питання раніше не задавали на цьому сайті, це було б чудовим питанням саме по собі.
— Kusalananda

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 у вхідному та зворотному куті на кінцях рядків.
— Скотт

@Scott гм, бо я просто сліпо скопіював текст з ОП. Дякую
— terdon

3
Це правильна відповідь. $(cat <<EOF ... EOF)це дивна конструкція: запустити нижню частину оболонки, а потім надіслати гередок коту просто так, що він надсилає її в STDOUT, а потім присвоює результат цієї підпакеті змінній? Я б хотів, щоб люди думали про те, що вони говорять про свої мислячі процеси. Присвоєння гередока змінній через readпорівняння є розумним.
— Багатий

Я б не сказав, що $(cat << EOF… (дані)… EOF )дивно. Це незручно і перекручено, але так read -d … << EOF - особливо read -d '' << EOF . Я високо ціную відповідь тердона, оскільки він використовує лише вбудовані програми, ніяких програм. Але, що ще важливіше, $(cat << EOF… (дані)… EOF )не вдається, якщо якісь рядки закінчуються \(зворотна косою рисою) - дивіться коментарі у відповіді Кусалаланда .
— Скотт

5

Це тому, що спосіб, який ви визначили тут-doc для використання з JSON, є неправильним. Вам потрібно використовувати його як

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

і це printf "$VALUE"повинно скинути JSON, як очікувалося.


3

Гередоки та змінні не змішуються добре або принаймні не так. Можна або…

Передайте гередок як стандартний вхід програми

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.