JSON 배열을 Bash로 변환

JSON 배열을 Bash로 변환

저는 JQ퀴즈 데이터베이스에서 일부 JSON을 가져오는 데 사용하고 있으며 결과를 구문 분석하고 싶습니다. 아래와 같이 결과 배열을 Bash에 저장하려고 하는데 형식이 Bash 스타일이 아닌 JavaScript/Python에서 사용하는 괄호 형식입니다.

quiz=$(curl -s https://opentdb.com/api.php?amount=3)
answers=$(echo $quiz | jq '[ .results][0][0].incorrect_answers')
correct=$(echo $quiz | jq '[ .results][0][0].correct_answer')
answers+=( $correct )

답변의 예는 다음과 같습니다.

[ "Excitement", "Aggression", "Exhaustion" ]

기형으로 인해 정답이 배열에 푸시되지 않습니다.

내 스크립트에서 배열로 해석되도록 위에 표시된 형식의 배열을 어떻게 변환할 수 있습니까?

출력 예curl (하드코딩되지 않아 질문과 답변이 매번 달라집니다):

{
  "response_code": 0,
  "results": [
    {
      "category": "Entertainment: Television",
      "type": "multiple",
      "difficulty": "easy",
      "question": "Which company has exclusive rights to air episodes of the "The Grand Tour"?",
      "correct_answer": "Amazon",
      "incorrect_answers": [
        "Netflix",
        "BBC",
        "CCTV"
      ]
    },
    {
      "category": "Celebrities",
      "type": "multiple",
      "difficulty": "medium",
      "question": "How much weight did Chris Pratt lose for his role as Star-Lord in "Guardians of the Galaxy"?",
      "correct_answer": "60 lbs",
      "incorrect_answers": [
        "30 lbs",
        "50 lbs",
        "70 lbs"
      ]
    },
    {
      "category": "Animals",
      "type": "boolean",
      "difficulty": "easy",
      "question": "The Killer Whale is considered a type of dolphin.",
      "correct_answer": "True",
      "incorrect_answers": [
        "False"
      ]
    }
  ]
}

답변1

jq결과를 한 줄씩 출력 하겠습니다 . 그런 다음 bash mapfile명령을 사용하여 행을 배열로 읽어옵니다.

mapfile -t correct < <(jq -r '.results[] | .correct_answer' <<<"$quiz")
declare -p correct
declare -a correct=([0]="Amazon" [1]="60 lbs" [2]="True")

오답의 경우 bash에는 다차원 배열이 없으므로 jq오답 배열을 CSV로 출력할 수 있습니다.

mapfile -t incorrect < <(jq -r '.results[] | .incorrect_answers | @csv' <<<"$quiz")
declare -p incorrect
declare -a incorrect=([0]="\"Netflix\",\"BBC\",\"CCTV\"" [1]="\"30 lbs\",\"50 lbs\",\"70 lbs\"" [2]="\"False\"")

그 다음에:

$ echo "q $i: ans=${correct[i]}; wrong=${incorrect[i]}"
q 1: ans=60 lbs; wrong="30 lbs","50 lbs","70 lbs"

문서:


사용자와 상호작용하고 있다고 가정합니다.

i=0
read -p "Answer to question $i: " answer

if [[ $answer == "${correct[i]}" ]]; then
    echo Correct
elif [[ ${incorrect[i]} == *"\"$answer\""* ]]; then
    echo Incorrect
else
    echo Invalid answer
fi

[[...]]연산자 ==내부 에는아니요문자열 항등 연산자는 다음과 같습니다.패턴 매칭운영자.

  • 첫 번째 테스트는 간단한 문자열 비교입니다.
  • 두 번째 테스트는 CVS 문자열에 잘못된 답이 포함되어 있는지 확인합니다.포함하다답변큰따옴표로 묶음

답변2

확대@로마 페레크레스트답변(지금처럼):

mapfile -t answers < <(jq -r '.results[] | [.correct_answer] + .incorrect_answers | @sh' <<<"$quiz")
declare -p answers
declare -a answers=([0]="'Amazon' 'Netflix' 'BBC' 'CCTV'" [1]="'60 lbs' '30 lbs' '50 lbs' '70 lbs'" [2]="'True' 'False'")

그러면 다음과 같은 것을 사용할 수 있습니다.

for i in "${!answers[@]}"; do
    declare -a "this_answers=( ${answers[i]} )"
    echo $i
    printf " > %s\n" "${this_answers[@]}"
done
0
 > Amazon
 > Netflix
 > BBC
 > CCTV
1
 > 60 lbs
 > 30 lbs
 > 50 lbs
 > 70 lbs
2
 > True
 > False

답변3

설정된 목표에 따라correct_answer"Bash 배열에 합계가 포함되기를 원합니다 incorrect_answers."결합된 값의 배열을 얻을 것으로 예상됩니다.
2개의 다른 명령을 실행하는 대신 jq전체 결합 시퀀스를 jq단일 표현식으로 구성할 수 있습니다.

~을 위한한 단어배열 항목:

$ declare -a answers=($(jq -r '[.results[0].correct_answer] + .results[0].incorrect_answers | @sh' <<<"$quiz"))

@sh:

입력은 POSIX 셸의 명령줄에서 사용하기 위해 이스케이프됩니다. 입력이 배열인 경우 출력은 공백으로 구분된 일련의 문자열입니다.

결과:

$ echo "${answers[2]}"
'BBC'
$ echo "${answers[0]}"
'Amazon'
$ echo "${answers[1]}"
'Netflix'
$ echo "${answers[@]}"
'Amazon' 'Netflix' 'BBC' 'CCTV'

공백이 있는 항목(예: 의 항목 .results[1])을 처리하려면 다음 방법 readarray@json옵션을 사용하십시오.

$ readarray -t answers < <(jq -r '[.results[1].correct_answer] + .results[1].incorrect_answers | .[] |@json' <<<"$quiz")

결과:

$ echo "${answers[1]}"
"30 lbs"
$ echo "${answers[0]}"
"60 lbs"
$ echo "${answers[@]}"
"60 lbs" "30 lbs" "50 lbs" "70 lbs"
$ echo "${answers[2]}"
"50 lbs"

답변4

results배열의 각 요소를 반복 하고 correct_answer각 요소의 값을 쉘 변수에 할당하고 incorrect_answers그 값을 다음 배열 변수에 할당한다고 가정합니다 bash.

#!/bin/bash

data=file.json

unset results
eval "$( jq -r '@sh "results=\(.results|length)"' "$data" )"
if [ -z "$results" ]; then
    echo 'Failed to parse number of results' >&2
    exit 1
fi

for (( i = 0; i < results; ++i )); do
    unset correct_answer
    unset incorrect_answers

    eval "$(
        jq -r --argjson i "$i" '
            .results[$i] |
            @sh "correct_answer=\(.correct_answer)",
            @sh "incorrect_answers+=(\(.incorrect_answers[]))"' "$data"
    )"

    printf 'The correct answer for question %d was "%s"\n' \
        "$((i+1))" "$correct_answer"
    echo 'The question had the following incorrect answers:'
    printf '\t"%s"\n' "${incorrect_answers[@]}"
done

질문의 데이터가 주어지면 다음이 출력됩니다.

The correct answer for question 1 was "Amazon"
The question had the following incorrect answers:
        "Netflix"
        "BBC"
        "CCTV"
The correct answer for question 2 was "60 lbs"
The question had the following incorrect answers:
        "30 lbs"
        "50 lbs"
        "70 lbs"
The correct answer for question 3 was "True"
The question had the following incorrect answers:
        "False"

각 반복에서 도구는 JSON 문서에서 배열의 특정 요소를 jq추출하는 데 사용됩니다 . results데이터를 셸 할당 집합으로 형식화합니다. 예를 들어, $i1이면 명령문이 생성됩니다.

correct_answer='60 lbs'
incorrect_answers+=('30 lbs')
incorrect_answers+=('50 lbs')
incorrect_answers+=('70 lbs')

그런 다음 쉘은 이러한 명령문을 평가하여 변수 correct_answer와 배열을 생성합니다 incorrect_answers.

관련 정보