将 JSON 数组转换为 Bash

将 JSON 数组转换为 Bash

我用来JQ从测验数据库中获取一些 JSON,并且我想解析结果。我试图在 Bash 中保存结果数组,如下所示,但格式是 JavaScript/Python 中使用的带方括号的格式,而不是 Bash 样式。

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行输出结果。然后使用 bashmapfile命令将行读入数组

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

按照既定目标“我希望 bash 数组包含correct_answerincorrect_answers您期望获得组合值的数组。
无需运行 2 个不同的jq命令,整个组合序列可以用一个jq表达式组成:

为了一个字数组项:

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

@sh

输入经过转义,适合在 POSIX shell 的命令行中使用。如果输入是数组,则输出将是一系列以空格分隔的字符串。

结果:

$ 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的值分配给 shell 变量,并将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"

在每次迭代中,该jq工具用于提取resultsJSON 文档中数组的特定元素。它将数据格式化为一组 shell 分配。例如,当$i为 1 时,它将创建语句

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

然后 shell 将计算这些语句,从而创建变量correct_answer和数组incorrect_answers

相关内容