bash & jq: 添加带有对象值的属性

huangapple go评论59阅读模式
英文:

bash & jq: add attribute with object value

问题

以下是翻译好的部分:

"我正在寻找一种方法将具有JSON对象值的新属性添加到现有的JSON文件中。

我的当前脚本:"

if [ ! -f "$src_file" ]; then
  echo "源文件 $src_file 不存在"
  exit 1
fi
if [ ! -f "$dst_file" ]; then
  echo "目标文件 $dst_file 不存在"
  exit 1
fi

if ! jq '.devDependencies' "$src_file" >/dev/null 2>&1; then
  echo "源文件 $src_file 中不存在键 'devDependencies'"
  exit 1
fi

dev_dependencies=$(jq '.devDependencies' "$src_file" | xargs )

# 从源文件提取数据
data=$(cat $src_file)

# 添加新的键值对
data=$(echo $data | jq --arg key "devDependencies" --arg value "$dev_dependencies" '. + {($key): ($value)}')

# 将数据写入目标文件
echo $data > $dst_file

"它正在工作,但$dev_dependencies中的devDependencies值被写为字符串:

"devDependencies": "{ @nrwl/esbuild: 15.6.3, @nrwl/eslint-pl[...]

如何将其写为原始JSON?"

英文:

I'm looking for a solution to add a new attribute with a JSON object value into an existing JSON file.

My current script:

if [ ! -f "$src_file" ]; then
  echo "Source file $src_file does not exists"
  exit 1
fi
if [ ! -f "$dst_file" ]; then
  echo "Destination file $dst_file does not exists"
  exit 1
fi

if ! jq '.devDependencies' "$src_file" >/dev/null 2>&1; then
  echo "The key "devDependencies" does not exists into source file $src_file"
  exit 1
fi

dev_dependencies=$(jq '.devDependencies' "$src_file" | xargs )

# Extract data from source file
data=$(cat $src_file)

# Add new key-value
data=$(echo $data | jq --arg key "devDependencies" --arg value "$dev_dependencies" '. + {($key): ($value)}')

# Write data into destination file
echo $data > $dst_file

It's working but the devDependencies value from $dev_dependencies is wrote as string:

"devDependencies": "{ @nrwl/esbuild: 15.6.3, @nrwl/eslint-pl[...]".

How can I write it as raw JSON ?

答案1

得分: 2

我认为你想要使用 --argjson 选项而不是 --arg。比较一下:

$ jq --arg k '{"foo": "bar"}' -n '{x: $k}'
{
  "x": "{\"foo\": \"bar\"}"
}

$ jq --argjson k '{"foo": "bar"}' -n '{x: $k}'
{
  "x": {
    "foo": "bar"
  }
}
英文:

I think you want the --argjson option instead of --arg. Compare

$ jq --arg k '{"foo": "bar"}' -n '{x: $k}'
{
  "x": "{\"foo\": \"bar\"}"
}

with

$ jq --argjson k '{"foo": "bar"}' -n '{x: $k}'
{
  "x": {
    "foo": "bar"
  }
}

答案2

得分: 1

--arg 会创建一个字符串变量。使用 --argjson 将值解析为 JSON(可以是对象、数组或数字)。

文档中得知:

--arg name value:

此选项将一个值传递给 jq 程序作为预定义变量。
如果你使用 --arg foo bar 运行 jq,那么 $foo 将在程序中可用,并具有值 "bar"。请注意,value 将被视为字符串,因此 --arg foo 123 将绑定 $foo"123"

命名参数也可作为 $ARGS.named 在 jq 程序中使用。

--argjson name JSON-text:

此选项将一个 JSON 编码的值传递给 jq 程序作为预定义变量。如果你使用 --argjson foo 123 运行 jq,那么 $foo 将在程序中可用,并具有值 123

注意,你不需要多次调用 jq、xargs、命令替代或变量(不要忘记在扩展时引用所有变量)。

要 "合并" 两个文件的内容,使用 jq 读取两个文件并让 jq 完成工作。这样可以避免在 jq 和 shell 上下文之间跳转产生的所有复杂情况。只需要一行代码:

jq --slurpfile deps "$dep_file" '. + { devDependencies: $deps[0].devDependencies }' "$source_file" > "$dest_file"

或者

jq --slurpfile deps "$dep_file" '. + ($deps[0]|{devDependencies})' "$source_file" > "$dest_file"

或者(仍然是一行代码):

jq --slurpfile deps "$dev_file" '.devDependencies = $deps[0].devDependencies' "$source_file" > "$dest_file"

此答案提醒了我非常有用的 input 过滤器,它可以使程序更短,因为它避免了使用变量:

jq '. + (input|{devDependencies})' "$source_file" "$dep_file" > "$dest_file"
英文:

--arg will create a string variable. Use --argjson to parse the value as JSON (can be object, array or number).

From the docs:

> ##### --arg name value:
>
> This option passes a value to the jq program as a predefined variable.
> If you run jq with --arg foo bar, then $foo is available in the
> program and has the value "bar". Note that value will be treated as a
> string, so --arg foo 123 will bind $foo to "123".
>
> Named arguments are also available to the jq program as $ARGS.named.
>
> ##### --argjson name JSON-text:
>
> This option passes a JSON-encoded value to the jq program as a
> predefined variable. If you run jq with --argjson foo 123, then $foo
> is available in the program and has the value 123.

Note that you don't need multiple invocations of jq, xargs, command substitution or variables (don't forget to quote all your variables when expanding).

To "merge" the contents of two files, read both files with jq and let jq do the work. This avoids all the complications that arise from jumping between jq and shell context. A single line is all that's needed:

jq --slurpfile deps "$dep_file" '. + { devDependencies: $deps[0].devDependencies }' "$source_file" > "$dest_file"

or

jq --slurpfile deps "$dep_file" '. + ($deps[0]|{devDependencies})' "$source_file" > "$dest_file"

alternatively (still a one-liner):

jq --slurpfile deps "$dev_file" '.devDependencies = $deps[0].devDependencies' "$source_file" > "$dest_file"

peak's answer here reminded me of the very useful input filter, which can make the program even shorter as it avoids the variable:

jq '. + (input|{devDependencies})' "$source_file" "$dep_file" > "$dest_file"

huangapple
  • 本文由 发表于 2023年2月8日 23:29:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/75388052.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定