JSON सरणी का उपयोग करके jq का उपयोग करके वैरिएबल को बैश करें


19

मुझे JSON सरणी मिली है जैसे:

{
  "SITE_DATA": {
    "URL": "example.com",
    "AUTHOR": "John Doe",
    "CREATED": "10/22/2017"
  }
}

मैं jq का उपयोग करके इस सरणी पर पुनरावृत्ति करना चाह रहा हूं, इसलिए मैं प्रत्येक आइटम की कुंजी को चर नाम और मान के रूप में सेट कर सकता हूं क्योंकि यह मूल्य है।

उदाहरण:

  • यूआरएल = "example.com"
  • AUTHOR = "जॉन डो"
  • बनाया = "2017/10/22"

मुझे अब तक जो भी मिला है वह सरणी पर पुनरावृत्त करता है लेकिन एक स्ट्रिंग बनाता है:

constants=$(cat ${1} | jq '.SITE_DATA' | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]")

कौन से आउटपुट:

URL=example.com
AUTHOR=John Doe
CREATED=10/22/2017

मैं स्क्रिप्ट में नीचे इन चर का उपयोग करना चाहता हूं:

echo ${URL}

लेकिन यह फिलहाल एक खाली आउटपुट है। मैं अनुमान लगा रहा हूं कि मुझे evalवहां कुछ चाहिए या नहीं, लेकिन मैं उस पर अपनी उंगली नहीं डाल सकता।

जवाबों:


29

आपका मूल संस्करण होने के लिए नहीं जा रहा है evalक्योंकि लेखक का नाम उस में रिक्त स्थान है सक्षम है - यह एक आदेश चलाकर रूप में दर्शाया जाएगा Doeवातावरण चर के साथ AUTHORकरने के लिए सेट John। वस्तुतः jqस्वयं को पाइप करने की आवश्यकता कभी नहीं होती है - आंतरिक पाइपिंग और डेटाफ़्लो अलग-अलग फ़िल्टर को एक साथ जोड़ सकते हैं।

आप jq प्रोग्राम का बहुत सरल संस्करण बना सकते हैं:

jq -r '.SITE_DATA | to_entries | .[] | .key + "=\"" + .value + "\""'

कौन से आउटपुट:

URL="example.com"
AUTHOR="John Doe"
CREATED="10/22/2017"

इसके लिए कोई आवश्यकता नहीं है map: .[]अलग-अलग आइटम के रूप में बाकी पाइपलाइन के माध्यम से सरणी में प्रत्येक वस्तु को लेने से संबंधित है , इसलिए अंतिम के बाद सब कुछ |अलग-अलग एक पर लागू होता है। अंत में, हम साधारण +मान के साथ एक वैध शेल असाइनमेंट स्ट्रिंग को इकट्ठा करते हैं , जिसमें मूल्य के आसपास के उद्धरण शामिल हैं।

यहां सभी पाइप मायने रखते हैं - उनके बिना आपको काफी अनपेक्षित त्रुटि संदेश मिलते हैं, जहां कार्यक्रम के कुछ हिस्सों का मूल्यांकन अलग-अलग संदर्भों में किया जाता है।

इस स्ट्रिंग है evalलंबे पात्रों के रूप में के रूप में सक्षम `, $, न्यू लाइन और रिक्त डाटा में दिखाई नहीं देते:

eval "$(jq -r '.SITE_DATA | to_entries | .[] | .key + "=\"" + .value + "\""' < data.json)"
echo "$AUTHOR"

उपयोग करते समय eval, सावधान रहें कि आप अपने द्वारा प्राप्त किए जा रहे डेटा पर भरोसा करते हैं, क्योंकि यह दुर्भावनापूर्ण है या सिर्फ एक अप्रत्याशित प्रारूप में चीजें बहुत गलत हो सकती हैं।


13

@ मिचेल होमर के उत्तर पर बिल्डिंग, आप evalडेटा को एक साहचर्य सरणी में पढ़कर संभावित-असुरक्षित से बच सकते हैं ।

उदाहरण के लिए, यदि आपका JSON डेटा नामक फ़ाइल में है file.json:

#!/bin/bash

typeset -A myarray

while IFS== read -r key value; do
    myarray["$key"]="$value"
done < <(jq -r '.SITE_DATA | to_entries | .[] | .key + "=" + .value ' file.json)

# show the array definition
typeset -p myarray

# make use of the array variables
echo "URL = '${myarray[URL]}'"
echo "CREATED = '${myarray[CREATED]}'"
echo "AUTHOR = '${myarray[URL]}'"

आउटपुट:

$ ./read-into-array.sh 
declare -A myarray=([CREATED]="10/22/2017" [AUTHOR]="John Doe" [URL]="example.com" )
URL = 'example.com'
CREATED = '10/22/2017'
AUTHOR = 'example.com'

1
आप एक सारणी के बिना भी मूल के रूप में अकेले काम कर सकते हैं declare -- “$key=$value”और $AUTHORआदि को अप्रत्यक्ष कर सकते हैं । यह अभी भी विकसित होने की तुलना में अधिक सुरक्षित है, हालांकि बदलना PATHया कुछ अभी भी इस संस्करण की तुलना में बहुत कम संभव है।
माइकल होमर

1
हाँ, सरणी अच्छी तरह से आपके चयन के एक कंटेनर में चर को अलग करती है - महत्वपूर्ण पर्यावरण चर के साथ गलती से / दुर्भावनापूर्ण रूप से गड़बड़ करने का कोई मौका नहीं। declare --अनुमत चर नामों की सूची के मुकाबले $ कुंजी की तुलना करके आप अपने संस्करण को सुरक्षित बना सकते हैं ।
कैस

1

बस एहसास हुआ कि मैं परिणामों पर लूप कर सकता हूं और प्रत्येक पुनरावृत्ति को निकाल सकता हूं:

constants=$(cat ${1} | jq '.SITE_DATA' | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]")

for key in ${constants}; do
  eval ${key}
done

मुझे करने की अनुमति देता है:

echo ${AUTHOR}
# outputs John Doe

0

मुझे वास्तव में @ मिचेल सुझाव पसंद है। कभी-कभी, आप BASH का उपयोग करके उस विशिष्ट सर्वर में किसी कार्य को निष्पादित करने के लिए वास्तव में सिर्फ कुछ चर मान निकाल सकते हैं। तो, वांछित चर पता है। इस दृष्टिकोण का उपयोग कर प्रति चर मान निर्धारित करने के लिए या एकाधिक कॉल से बचने या यहां तक ​​कि कई चर के साथ रीड स्टेटमेंट का उपयोग करने का तरीका है जिसमें कुछ मान्य और खाली हो सकते हैं, जिससे मूल्य शिफ्ट हो सकता है (यह मेरी समस्या थी)

मेरे पिछले दृष्टिकोण से लीड वैल्यू शिफ्ट एरर आएगी, अगर .svID [] .ID = "" ( sv को स्लॉट की वैल्यू मिलेगी)

-rd '\n' getInfo sv slotID <<< $(jq -r '(.infoCMD // "no info"), (.svID[].ID // "none"), (._id // "eeeeee")' <<< $data)

यदि आपने कर्ल का उपयोग करके ऑब्जेक्ट डाउनलोड किया है, तो मेरा दृष्टिकोण कुछ वैरिएबल को एक अनुकूल नाम में बदलने के लिए है क्योंकि डेटा सरणियों से डेटा निकालें।

eval और फिल्टर्स का उपयोग करने से समस्या एक लाइन से हल हो जाएगी और वांछित नाम के साथ चर का उत्पादन होगा

eval "$(jq -r '.[0] | {varNameExactasJson, renamedVar1: .var1toBeRenamed, varfromArray: .array[0].var, varValueFilter: (.array[0].textVar|ascii_downcase)} | to_entries | .[] | .key + "=\"" + (.value | tostring) + "\""' <<< /path/to/file/with/object )"  

इस मामले में लाभ, यह तथ्य है कि यह पहले चरण में सभी वांछित चर को फ़िल्टर, नाम बदलने, प्रारूपित करेगा। निरीक्षण करें कि वहाँ है। [0] | अगर GET का उपयोग करके RESTFULL API सर्वर से स्रोत, प्रतिक्रिया डेटा के रूप में है तो यह होना बहुत आम है:

[{"varNameExactasJson":"this value", "var1toBeRenamed: 1500, ....}]

यदि आपका डेटा किसी सरणी से नहीं है, अर्थात। एक वस्तु की तरह है:

{"varNameExactasJson":"this value", "var1toBeRenamed: 1500, ....}

बस प्रारंभिक सूचकांक निकालें:

eval "$(jq -r '{varNameExactasJson, renamedVar1: .var1toBeRenamed, varfromArray: .array[0].var, varValueFilter: (.array[0].textVar|ascii_downcase)} | to_entries | .[] | .key + "=\"" + (.value | tostring) + "\""' <<< /path/to/file/with/object )"  

यह एक पुराना सवाल है, लेकिन मैंने इसे साझा करना महसूस किया, क्योंकि इसे खोजना मुश्किल था

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.