Mengapa konten JSON dari heredoc tidak dapat diuraikan?


11

Saya memiliki fragmen JSON.

Berikut ini tidak berfungsi:

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

Hasilnya adalah:

Tidak ada objek JSON yang bisa diterjemahkan

Melakukan hal yang sama dengan jq, yaitu

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

Tidak ada output.

Ada perilaku yang sama untuk yang berikut:

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

Tanggapan:

Tidak ada objek JSON yang bisa diterjemahkan

Tetapi berikut ini berfungsi:

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

5
Saya tidak tahu apa yang dilakukan bash, tetapi ada koma di belakang setelah string email di dua string pertama Anda tetapi tidak pada yang ketiga, yang akan membuat pasangan pertama ilegal JSON
Nick T

@NickT Anda harus membuat jawaban karena saya pikir itulah masalahnya.
rrauenza

Jika itulah (satu-satunya) jawaban itu mungkin harus ditutup karena "tidak dapat direproduksi (salah ketik)". Namun, sepertinya jawaban Kusa dan terdon menyebutkan penugasan + redirection benar-benar rusak sehingga Anda mendapatkan string kosong, jadi ada dua masalah, keduanya akan memberikan kesalahan "No JSON ..." yang sama. Ini adalah praktik yang sangat baik untuk membagi dua masalah dengan memeriksa asumsi Anda di tengah: yang sederhana echo $VALUEtanpa ... | jqakan informatif.
Nick T

@NickT: Itu masalah copy / paste. Maaf atas kebingungan
Jim

Jawaban:


19
VALUE=<<PERSON
some data
PERSON

echo "$VALUE"

Tidak ada output.

Dokumen di sini adalah pengalihan , Anda tidak dapat mengarahkan ulang ke variabel.

Ketika baris perintah diuraikan, pengalihan ditangani dalam langkah terpisah dari penugasan variabel. Karena itu perintah Anda setara dengan (perhatikan spasi)

VALUE= <<PERSON
some data
PERSON

Yaitu, ia memberikan string kosong ke variabel Anda, kemudian mengarahkan input standar dari string-sini ke dalam perintah (tetapi tidak ada perintah, jadi tidak ada yang terjadi).

Catat itu

<<PERSON
some data
PERSON

valid, sebagaimana adanya

<somefile

Hanya saja tidak ada perintah yang aliran input standarnya dapat diatur untuk berisi data, sehingga hilang begitu saja.

Ini akan berhasil:

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

Di sini, perintah yang menerima dokumen-sini adalah cat, dan menyalinnya ke output standarnya. Inilah yang kemudian ditugaskan ke variabel melalui substitusi perintah.

Dalam kasus Anda, Anda bisa menggunakan

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

tanpa mengambil langkah ekstra menyimpan data dalam suatu variabel.


2
Anda juga bisa hanya PERSON="diikuti oleh baris baru dan data multi-baris, lalu yang lain "di akhir.
R .. GitHub BERHENTI MEMBANTU ICE

1
@ R .. Ya, tetapi dokumen di sini memungkinkan Anda untuk mem-bypass aturan penawaran shell. Oleh karena itu seringkali lebih aman untuk menggunakan dokumen di sini daripada string yang dikutip untuk data multi-line, terutama jika data tersebut berisi penawaran tunggal atau ganda (atau keduanya).
Kusalananda

2
@R .. Mengingat ini adalah JSON yang sedang kita bicarakan, mungkin lebih baik menggunakan tanda kutip tunggal untuk tidak harus melepaskan diri dari tanda kutip ganda dari setiap nama properti. PERSON='. Itu kecuali OP ingin menginterpolasi variabel nanti.
JoL

(backslash) (baris baru) tampaknya hilang dalam dokumen di sini, bahkan jika Anda mengutip / menghindari kata pembatas. Itu mungkin diinginkan, tetapi apakah ada cara untuk menonaktifkannya?
Scott

@Scott Jika pertanyaan itu belum pernah diajukan di situs ini sebelumnya, itu akan menjadi pertanyaan yang sangat bagus.
Kusalananda

11

Karena variabel tidak disetel oleh heredoc Anda:

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

$

Jika Anda ingin menggunakan heredoc untuk memberikan nilai pada variabel, Anda perlu sesuatu seperti:

$ read -d '' -r VALUE <<PERSON  
{    
  "type": "account",  
  "customer_id": "1234",  
  "customer_email": "jim@gmail.com",  
}   
PERSON

1
Mengapa Anda membungkus data JSON dalam tanda kutip tunggal? Itu tidak benar-benar terlihat seperti OP ingin mereka menjadi bagian dari string masukannya. Selain itu, +1 untuk mengurangi populasi kucing tunawisma. Seperti dengan jawaban Kusalananda, Anda mungkin ingin menyarankan << \PERSONuntuk melindungi terhadap $input dan backslash di ujung baris.
Scott

@ Hemat um, karena saya hanya membabi buta menyalin teks dari OP. Terima kasih
terdon

3
Ini adalah jawaban yang benar. $(cat <<EOF ... EOF)itu konstruk yang aneh: menjalankan subkulit dan kemudian mengirim heredoc ke kucing sehingga mengirimkannya ke STDOUT dan kemudian menetapkan hasil subkulit itu ke variabel? Saya berharap orang berpikir tentang apa yang mereka katakan tentang proses pemikiran mereka. Menetapkan heredoc ke variabel melalui read, sebagai perbandingan, adalah waras.
Kaya

Saya tidak akan mengatakan bahwa $(cat << EOF... (data) ... EOF )aneh. Ini canggung dan berbelit-belit, tetapi begitu read -d … << EOF - terutama read -d '' << EOF . Saya menghargai jawaban terdon karena hanya menggunakan builtin, tidak ada program. Tetapi, yang lebih penting, $(cat << EOF... (data) ... EOF )gagal jika ada garis yang diakhiri dengan \(garis miring terbalik) - lihat komentar di bawah jawaban Kusalananda .
Scott

5

Itu karena cara Anda mendefinisikan dokumen di sini untuk digunakan dengan JSON salah. Anda harus menggunakannya sebagai

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

dan melakukan printf "$VALUE"harus membuang JSON seperti yang diharapkan.


3

Variabel dan variabel Hered tidak tercampur dengan baik atau setidaknya tidak dengan cara ini. Anda bisa ...

Lulus heredoc sebagai input standar aplikasi

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

atau…

Menyimpan teks multi-baris dalam variabel shell

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

Saya menggunakan tanda kutip tunggal untuk menghindari perlunya lolos dari tanda kutip ganda batin. Tentu saja Anda juga dapat menggunakan tanda kutip ganda, misalnya jika Anda perlu memperluas parameter:

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

Kemudian Anda bisa menggunakan nilai variabel nanti.

echo -n "$VALUE" | python -m json.tool
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.