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 / 问题 / 413878
Accepted
EHerman
EHerman
Asked: 2017-12-31 14:50:58 +0800 CST2017-12-31 14:50:58 +0800 CST 2017-12-31 14:50:58 +0800 CST

JSON数组使用jq来bash变量

  • 772

我有一个像这样的 JSON 数组:

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

我希望使用 jq 迭代这个数组,这样我就可以将每个项目的键设置为变量名,并将值设置为它的值。

例子:

  • URL="example.com"
  • 作者=“约翰·多伊”
  • 已创建="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或一些东西,但似乎无法将我的手指放在它上面。

bash jq
  • 4 4 个回答
  • 58761 Views

4 个回答

  • Voted
  1. Best Answer
    Michael Homer
    2017-12-31T15:10:04+08:002017-12-31T15:10:04+08:00

    您的原始版本将eval无法使用,因为作者姓名中有空格 - 它会被解释为运行Doe环境变量AUTHOR设置为John. 几乎也不需要通过管道jq连接自己——内部管道和数据流可以将不同的过滤器连接在一起。

    所有这些只有在您完全信任输入数据(例如,它是由您控制的工具生成)时才有意义。下面详细说明了几个可能的问题,但我们假设数据本身肯定是您目前期望的格式。

    您可以制作一个更简单的 jq 程序版本:

    jq -r '.SITE_DATA | to_entries | .[] | .key + "=" + (.value | @sh)'
    

    输出:

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

    不需要 a map:.[]处理通过管道的其余部分将数组中的每个对象作为单独的 item处理,因此最后一个之后的所有内容都|分别应用于每个对象。最后,我们只是用普通的连接组装一个有效的 shell 赋值字符串+,包括适当的引号和在值周围转义@sh。

    这里所有的管道都很重要——没有它们你会得到相当无用的错误消息,程序的某些部分是在微妙不同的上下文中评估的。

    如果您完全信任输入数据并具有您想要的效果,则此字符串eval可以:

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

    与以往一样使用 时eval,请注意您要信任所获得的数据,因为如果它是恶意的或只是以意外的格式出现,事情可能会非常错误。特别是,如果键包含 shell 元字符$或空格,这可能会创建一个正在运行的命令。例如,它还可能PATH意外覆盖环境变量。

    如果你不信任数据,要么根本不这样做,要么过滤对象以只包含你首先想要的键:

    jq '.SITE_DATA | { AUTHOR, URL, CREATED } | ...'
    

    如果值是一个数组,您也可能会遇到问题,所以.value | tostring | @sh会更好 - 但是这个警告列表可能是一个很好的理由,首先不要这样做。


    也可以建立一个关联数组,而不是引用键和值:

    eval "declare -A data=($(jq -r '.SITE_DATA | to_entries | .[] | @sh "[\(.key)]=\(.value)"' < test.json))"
    

    在此之后,${data[CREATED]}包含创建日期等,无论键或值的内容是什么。这是最安全的选项,但不会导致可以导出的顶级变量。当一个值是一个数组时,它仍然可能产生 Bash 语法错误,或者如果它是一个对象,它可能会产生一个 jq 错误,但不会执行代码或覆盖任何东西。

    • 45
  2. cas
    2017-12-31T18:36:59+08:002017-12-31T18:36:59+08:00

    基于@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'
    
    • 19
  3. EHerman
    2017-12-31T14:54:28+08:002017-12-31T14:54:28+08:00

    刚刚意识到我可以遍历结果并评估每次迭代:

    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
    
    • 3
  4. Thiago Conrado
    2019-08-28T12:01:47+08:002019-08-28T12:01:47+08:00

    我真的很喜欢@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 和 filters 将用一行解决问题,并生成具有所需名称的变量。

    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 的 RESTful 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 )"
    
    • 0

相关问题

  • jq 使用多个 --arg 添加或更新一个值

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

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

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

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

Sidebar

Stats

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

    JSON数组使用jq来bash变量

    • 4 个回答
  • Marko Smith

    日期可以为 GMT 时区格式化当前时间吗?[复制]

    • 2 个回答
  • Marko Smith

    bash + 通过 bash 脚本从文件中读取变量和值

    • 4 个回答
  • Marko Smith

    如何复制目录并在同一命令中重命名它?

    • 4 个回答
  • Marko Smith

    ssh 连接。X11 连接因身份验证错误而被拒绝

    • 3 个回答
  • Marko Smith

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

    • 7 个回答
  • Marko Smith

    systemctl 命令在 RHEL 6 中不起作用

    • 3 个回答
  • Marko Smith

    rsync 端口 22 和 873 使用

    • 2 个回答
  • Marko Smith

    以 100% 的利用率捕捉 /dev/loop -- 没有可用空间

    • 1 个回答
  • Marko Smith

    jq 打印子对象中所有的键和值

    • 2 个回答
  • Martin Hope
    EHerman JSON数组使用jq来bash变量 2017-12-31 14:50:58 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Drux 日期可以为 GMT 时区格式化当前时间吗?[复制] 2017-12-26 11:35:07 +0800 CST
  • Martin Hope
    AllisonC 如何复制目录并在同一命令中重命名它? 2017-12-22 05:28:06 +0800 CST
  • Martin Hope
    Steve “root”用户的文件权限如何工作? 2017-12-22 02:46:01 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST
  • Martin Hope
    Cbhihe 将默认编辑器更改为 vim for _ sudo systemctl edit [unit-file] _ 2017-12-03 10:11:38 +0800 CST
  • Martin Hope
    showkey 如何下载软件包而不是使用 apt-get 命令安装它? 2017-12-03 02:15:02 +0800 CST
  • Martin Hope
    youxiao 为什么目录 /home、/usr、/var 等都具有相同的 inode 编号 (2)? 2017-12-02 05:33:41 +0800 CST
  • Martin Hope
    user223600 gpg —list-keys 命令在将私钥导入全新安装后输出 uid [未知] 2017-11-26 18:26:02 +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