เหตุใดเนื้อหา 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 ผิดกฎหมาย
Nick T

@NickT คุณควรตอบคำถามนี้เพราะฉันคิดว่านั่นเป็นปัญหา
ruuenza

หากนั่นคือคำตอบ (แต่เพียงผู้เดียว) ก็น่าจะปิดได้เพราะ "ไม่สามารถทำซ้ำได้ (ตัวพิมพ์)" อย่างไรก็ตามดูเหมือนว่าคำตอบของ Kusa และ terdon จะกล่าวถึงการมอบหมาย + การเปลี่ยนเส้นทางเสียทั้งหมดดังนั้นคุณจึงได้รับสตริงว่างดังนั้นจึงมีสองปัญหาซึ่งทั้งสองอย่างนี้จะให้ข้อผิดพลาด "ไม่ JSON ... " เหมือนกัน เป็นวิธีปฏิบัติที่ดีมากในการแบ่งปัญหาโดยการตรวจสอบสมมติฐานของคุณตรงกลาง: แบบง่าย ๆecho $VALUEโดยไม่มี ... | jqข้อมูล
Nick T

@NickT: นั่นเป็นปัญหาการคัดลอก / วาง ขออภัยในความสับสน
Jim

คำตอบ:


19
VALUE=<<PERSON
some data
PERSON

echo "$VALUE"

ไม่มีเอาต์พุต

เอกสารที่นี่เป็นการเปลี่ยนเส้นทางคุณไม่สามารถเปลี่ยนเส้นทางเป็นตัวแปรได้

เมื่อวิเคราะห์บรรทัดคำสั่งการเปลี่ยนเส้นทางจะถูกจัดการในขั้นตอนแยกต่างหากจากการกำหนดตัวแปร คำสั่งของคุณเทียบเท่ากับ (สังเกตพื้นที่)

VALUE= <<PERSON
some data
PERSON

นั่นคือมันกำหนดสตริงว่างให้กับตัวแปรของคุณจากนั้นเปลี่ยนทิศทางอินพุตมาตรฐานจาก here-string ไปที่คำสั่ง (แต่ไม่มีคำสั่งดังนั้นจึงไม่มีอะไรเกิดขึ้น)

สังเกตได้ว่า

<<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="ตามด้วยการขึ้นบรรทัดใหม่และข้อมูลหลายบรรทัดจากนั้นอีกบรรทัด"ในตอนท้าย
.. GitHub หยุดช่วยน้ำแข็ง

1
@R .. ใช่ แต่ที่นี่เอกสารช่วยให้คุณสามารถข้ามกฎการอ้างอิงของเปลือก ดังนั้นจึงมักจะปลอดภัยกว่าที่จะใช้เอกสารที่นี่แทนสตริงที่ยกมาสำหรับข้อมูลหลายบรรทัดโดยเฉพาะถ้าข้อมูลมีเครื่องหมายคำพูดเดี่ยวหรือคู่ (หรือทั้งสอง)
Kusalananda

2
@R .. เนื่องจากเป็น JSON เรากำลังพูดถึงมันอาจจะดีกว่าที่จะใช้อัญประกาศเดี่ยวเพื่อไม่ต้องหลีกเลี่ยงอัญประกาศคู่ของชื่อคุณสมบัติแต่ละชื่อ PERSON='. นั่นคือนอกเสียจาก OP ต้องการแก้ไขตัวแปรในภายหลัง
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 ด้วยเครื่องหมายคำพูดเดี่ยว? ดูเหมือนว่า OP จะไม่ต้องการให้พวกเขาเป็นส่วนหนึ่งของสายป้อนข้อมูลของเขา นอกเหนือจากนั้น +1 สำหรับการลดจำนวนประชากรแมวจรจัด เช่นเดียวกับคำตอบของ Kusalananda คุณอาจต้องการแนะนำ<< \PERSONให้ป้องกัน$s ในอินพุตและแบ็กสแลชที่ปลายบรรทัด
สกอตต์

@Scott อืมเพราะฉันเพิ่งคัดลอกข้อความจาก OP ขอบคุณ
terdon

3
นี่คือคำตอบที่ถูกต้อง $(cat <<EOF ... EOF)เป็นโครงสร้างที่แปลกประหลาด: เรียกใช้ subshell แล้วส่ง heredoc เพื่อ cat เพียงเพื่อส่งไปยัง STDOUT แล้วกำหนดผลลัพธ์ของ subshell นั้นให้กับตัวแปรหรือไม่ ฉันหวังว่าผู้คนจะคิดถึงสิ่งที่พวกเขาพูดเกี่ยวกับกระบวนการคิดของพวกเขา การกำหนด heredoc ให้กับตัวแปรผ่านreadการเปรียบเทียบนั้นมีเหตุผล
รวย

ฉันจะไม่พูดว่า$(cat << EOF… (ข้อมูล) … EOF )เป็นเรื่องแปลก มันอึดอัดและซับซ้อน แต่เพื่อให้เป็นread -d … << EOF - read -d '' << EOF โดยเฉพาะอย่างยิ่ง ฉันขอขอบคุณคำตอบของ terdon เพราะมันใช้งานได้เฉพาะในตัวเท่านั้นไม่มีโปรแกรม แต่ที่สำคัญกว่า$(cat << EOF... (ข้อมูล) ... EOF )ล้มเหลวถ้าเส้นใด ๆ จบลงด้วย\(ทับขวา) - ดูความคิดเห็นภายใต้คำตอบ Kusalananda ของ
สกอตต์

5

เป็นเพราะวิธีที่คุณกำหนด here-doc เพื่อใช้กับ JSON นั้นผิด คุณต้องใช้มันเป็น

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

และการทำprintf "$VALUE"ควรทิ้ง JSON ตามที่คาดไว้


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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.