shell 使用jq如何将多个值作为参数传递给函数?

wtzytmuj  于 2022-11-16  发布在  Shell
关注(0)|答案(2)|浏览(246)

我有一个json文件test.json,其内容为:

[
{
  "name": "Akshay",
  "id": "234"
},
{
  "name": "Amit",
  "id": "28"
}
]

我有一个shell脚本,其中包含以下内容:

#!/bin/bash
function display
{
  echo "name is $1 and id is $2"
}

cat test.json | jq '.[].name,.[].id' | while read line; do display $line; done

我希望将单个项目的名称和ID作为参数一起传递给函数display,但输出如下所示:

name is "Akshay" and id is 
name is "Amit" and id is   
name is "234" and id is 
name is "28" and id is

正确的代码实现方式应该是什么?PS:我特别想使用jq,所以请根据jq回答

pftdvrlh

pftdvrlh1#

下面是两个主要问题和一些附加项,它们对于当前的示例用例可能无关紧要,但在处理来自不可信来源的真实数据时可能非常重要:

  • 您当前的代码在写入 * 任何 * id之前迭代 * 所有 * name
  • 您当前的代码使用了换行符,但没有努力将多行读入每个while循环迭代。
  • 您的代码使用换行符,但换行符可以出现在字符串中;因此,这限制了输入域。
  • 当您通过管道进入while循环时,该循环在子shell中运行;当管道退出时,subshell也退出,因此循环设置的所有变量都将丢失。
  • 与让jq直接从test.json读取数据相比,启动/bin/cat的副本并让jq从其输出中读取管道是愚蠢和低效的。

我们可以解决所有这些问题:

  • 要将name s和id s成对写入,您需要更类似于jq '.[] | (.name, .id)'的内容
  • 要读取循环中每个元素的name和id,需要while IFS= read -r name && IFS= read -r id; do ...迭代这些元素对。
  • 从换行符切换到NULL(NUL是唯一不能存在于C字符串中的字符,因此是bash字符串),您可能希望使用jq-j参数,然后向正在编写的内容中添加显式的"\u0000"元素。您需要为每个read添加-d ''参数。
  • 要将while read循环移出subshell,我们可以使用process substitution,如BashFAQ #24中所述。
  • 要让jq直接从test.json读取,可以使用<test.json让shell将文件直接连接到jq的stdin,或者在jq的命令行上传递文件名。

以一种对包含JSON编码的NULL的输入数据具有鲁棒性的方式执行上面描述的所有操作将如下所示:

#!/bin/bash
display() {
  echo "name is $1 and id is $2"
}

cat >test.json <<'EOF'
[
  { "name": "Akshay", "id": "234" },
  { "name": "Amit", "id": "28" }
]
EOF

while IFS= read -r -d '' name && IFS= read -r -d '' id; do
  display "$name" "$id"
done < <(jq -j '
  def stripnuls: sub("\u0000"; "<NUL>");
  .[] | ((.name | stripnuls), "\u0000", (.id | stripnuls), "\u0000")
' <test.json)

您可以在www.example.com上看到上面运行的代码https://replit.com/@CharlesDuffy2/BelovedForestgreenUnits#main.sh

uklbhaso

uklbhaso2#

可以使用字符串插值。

jq '.[] | "The name is \(.name) and id \(.id)"'

结果:

"The name is Akshay and id 234"
"The name is Amit and id 28"
"The name is hi and id 28"

如果要去掉每个对象的双引号,则:

jq --raw-output '.[] | "The name is \(.name) and is \(.id)"'

https://jqplay.org/s/-lkpHROTBk0

相关问题