jq를 사용하여 변수를 bash하는 JSON 배열


19

다음과 같은 JSON 배열이 있습니다.

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

jq를 사용 하여이 배열을 반복하여 각 항목의 키를 변수 이름으로 설정하고 값을 값으로 설정할 수 있습니다.

예:

  • URL = "example.com"
  • AUTHOR = "존도"
  • CREATED = "10/22/2017"

지금까지 내가 배열을 반복하지만 문자열을 만듭니다.

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긴 문자로 같은 수 `, $, 줄 바꿈 및 널 (null)이 데이터에 표시되지 않습니다 :

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

를 사용 eval하는 경우, 악의적이거나 예상치 못한 형식의 데이터로 인해 잘못 될 수 있으므로 수신하는 데이터를 신뢰해야합니다.


13

@Michael Homer의 답변을 바탕으로 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이 버전보다 변경 이나 무언가가 여전히 덜 가능 하지만 여전히 eval보다 안전 합니다.
Michael Homer

1
예, 배열은 변수를 선택한 컨테이너로 멋지게 분리합니다. 실수로 / 악의적으로 중요한 환경 변수를 망칠 가능성이 없습니다. declare --$ key를 허용 된 변수 이름 목록과 비교 하여 버전을 안전하게 만들 수 있습니다.
cas

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

나는 @Michel 제안을 정말로 좋아한다. 때로는 BASH를 사용하여 특정 서버에서 작업을 실행하기 위해 일부 변수 값을 추출 할 수도 있습니다. 따라서 원하는 변수를 알고 있습니다. 이 접근 방식을 사용하는 것은 변수 당 값을 설정하기 위해 jq를 여러 번 호출하거나 여러 변수가있는 read 문을 사용하여 일부 변수가 유효하고 비어있을 수있는 방법입니다.

리드 값 시프트 오류 .svID [] .ID 경우 = ""(로 이어질 것입니다 내 이전 방식 SV 얻을 것이다 slotID의

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

curl을 사용하여 객체를 다운로드 한 경우 데이터 배열에서 데이터를 추출 할 때 일부 변수의 이름을 알기 쉬운 이름으로 바꾸는 방법이 있습니다.

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 )"  

이것은 오래된 질문이지만 찾기가 어려워서 나눔을 느꼈습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.