AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 553445
Accepted
Philip Kirkbride
Philip Kirkbride
Asked: 2019-11-22 12:30:40 +0800 CST2019-11-22 12:30:40 +0800 CST 2019-11-22 12:30:40 +0800 CST

将 JSON 数组转换为 Bash

  • 772

我正在使用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"
      ]
    }
  ]
}
bash shell-script
  • 5 5 个回答
  • 8047 Views

5 个回答

  • Voted
  1. glenn jackman
    2019-11-22T12:46:03+08:002019-11-22T12:46:03+08:00

    我会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 字符串是否包含双引号中的答案
    • 5
  2. glenn jackman
    2019-11-22T13:10:17+08:002019-11-22T13:10:17+08:00

    扩展@ RomanPerekhrest的答案(现在就去投票吧):

    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
    
    • 2
  3. Best Answer
    RomanPerekhrest
    2019-11-22T12:59:37+08:002019-11-22T12:59:37+08:00

    根据既定目标“我希望 bash 数组包含correct_answer并且incorrect_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"
    
    • 1
  4. glenn jackman
    2019-11-22T13:39:20+08:002019-11-22T13:39:20+08:00

    因为这个问题在我的脑海中提出,一个运行游戏的小脚本:

    #!/usr/bin/env bash
    
    main() {
        local -a questions
        mapfile -t questions < <(
            get_quiz |
            jq -r '.results[] | [.question] + [.correct_answer] + .incorrect_answers | @sh'
        )
    
        for i in "${!questions[@]}"; do
            local -a q="( ${questions[i]} )"
            question $((i+1)) "${q[@]}"
        done
    }
    
    question() {
        local num=$1 question=$2 correct=$3
        local -a answers=("${@:3}")
    
        # shuffle the answers
        mapfile -t answers < <(printf "%s\n" "${answers[@]}" | sort -R)
    
        echo
        echo "Question #$num"
        PS3="${question//&quot;/\'} "
    
        select answer in "${answers[@]}"; do
            if [[ $answer == "$correct" ]]; then
                echo "Correct"
                break
            fi
            echo "Incorrect"
        done
    }
    
    get_quiz() {
        # this is where you'd do your curl call, but 
        # for now, the sample data is printed.
        cat << 'JSON'
        {
          "response_code": 0,
          "results": [
            {
              "category": "Entertainment: Television",
              "type": "multiple",
              "difficulty": "easy",
              "question": "Which company has exclusive rights to air episodes of the &quot;The Grand Tour&quot;?",
              "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 &quot;Guardians of the Galaxy&quot;?",
              "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"
              ]
            }
          ]
        }
    JSON
    }
    
    main
    
    • 1
  5. Kusalananda
    2021-07-24T00:17:27+08:002021-07-24T00:17:27+08:00

    假设您要遍历results数组中的每个元素,并将每个元素的correct_answer值分配给 shell 变量,并将incorrect_answers值分配给数组变量 in 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。

    • 0

相关问题

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • MySQL Select with function IN () with bash array

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve