0

json can be created using the following command.

  jq -n \
  --arg v1 "Value1" \
  --arg v2 "Value2" \
  '{k1: "$v1", k2:$v2'}

But when my key is mutable, how should I loop? For example, the script I execute is

test.sh k1=v1 k2=v2 k3=v3

test.sh is as follows

index=1
while ((index <= "$#")); do
  data_i_key=$(echo ${!index} | awk -F "=" '{print $1}')
  data_i_value=$(echo ${!index} | awk -F "=" '{print $2}')
  let index++
  JSON_STRING=$(jq -n \
    --arg value "$data_i_value" \
    '{'"$data_i_key"': $value'})
    echo $JSON_STRING

The above print result is

{ "K3": "V3" }

if I replace it with

JSON_STRING+=$(jq -n \
    --arg val_value "$dataValue" \
    '{'"$data_i_key"': $val_value'})

The print result is

{ "k1": "v1" }{ "k2": "v2" }{ "K3": "V3" }

The above two methods have not achieved the goal, do you have a good way to deal with it? My desired output is

{ "k1": "v1" , "k2": "v2" ,"K3": "V3" }

hope you can help me.

1
  • How does the script decide when to upper-case key and value? k1, v1, k2, v2 are inserted verbatim into the JSON, but k3 and v3 are uppercased to K3 and V3. Intentional or typo? Commented Oct 17, 2022 at 11:02

3 Answers 3

3

I'd suggest a totally different, but simpler, approach:

for kv; do
  echo "$kv" | jq -R './"=" | {key:first,value:last}'
done | jq -s 'from_entries'

It builds {key: …, value: …} objects from your positional parameters (splitting them by the equal sign) and then slurping all those objects in a second jq process, converting them into a single object via from_entries.

Alternatively, using -n (--null-input), --args and then accessing via $ARGS.positional. This avoids the loop and the second jq call altogether.

jq -n '$ARGS.positional | map(./"=" | {key:first,value:last}) | from_entries' --args "$@"

If your values can contain = themselves, you have to join all but the first value of the array:

jq -n '$ARGS.positional
| map(./"=" | {key:first,value:.[1:]|join("=")})
| from_entries' --args "$@"
Sign up to request clarification or add additional context in comments.

12 Comments

Going further: jq -n --args '$ARGS.positional | map(. / "=" | {key:first, value:last}) | from_entries' k1=v1 k2=v2 k 3=v3 (or … "$@")
@pmf you are too fast, I was already extending my answer :)
Thanks a lot for your answer, but I don't quite understand how $ARGS.positional is used? If I only want to construct json from the second parameter, how should I modify it?
@junhu what do you mean with "only json from the second parameter?"
Or, avoiding the need for from_entries => echo k1=v1 k2=v2 k3=v3 | jq -R './" " | map(./"=" | {(first): last}) | add'
|
0

Use parentheses around the key expression to have it evaluated:

jq -n --arg k1 "Key1" --arg v1 "Value1" '{($k1): $v1}'
{
  "Key1": "Value1"
}

1 Comment

I know this method, but now I want to write all the parameters together in json format in the loop and assign them to JSON_STRING。
-1

Perhaps this, which will handle an arbitrary number of key=value arguments:

#!/usr/bin/env bash

args=()
for arg; do
    IFS="=" read -r k v <<<"$arg"
    args+=("$k" "$v")
done

jq -n --args '
    $ARGS.positional as $a
    | reduce range(0; $a | length; 2) as $i ({}; .[$a[$i]] = $a[$i + 1])
' "${args[@]}"

Produces:

$ ./test.sh k1=v1 k2=v2 k3=v3
{
  "k1": "v1",
  "k2": "v2",
  "k3": "v3"
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.