Чому вміст 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.