Добавить пары ключ:значение в объект JSON в Bash

Я хотел бы добавить несколько пар ключ: значение в существующую строку JSON. Значения передаются в мой скрипт в качестве аргументов командной строки.

Пока что у меня есть это

data='{"update": { "labels": [] } }'

for label in "${@}";do
   objJSON=$(printf '%s\n' "{ "add": ${label} }" | jq -R . | jq -s .)
   data=$(echo ${data} | jq  --argjson jsonString "$objJSON" '.update.labels += $jsonString')
done
echo ${data} >output.txt

jq --color-output . output.txt

Мой вывод таков:

{
  "update": {
    "labels": [
      "{ add: value1 }",
      "{ add: value2 }"
    ]
  }
}

но я пытаюсь получить это (обратите внимание на кавычки вокруг add и каждого значения):

{
  "update": {
    "labels": [
      { "add": "value1" },
      { "add": "value2" }
    ]
  }
}

Я не понимаю, где я ошибаюсь. Может кто-нибудь помочь, пожалуйста?

Re: «Я не понимаю, в чем я ошибаюсь»: printf '%s\n' "{ "add": ${label} }" выдает что-то вроде { add: value2 } (который не является допустимым JSON, поскольку в нем отсутствуют кавычки вокруг строк ключа и значения), который затем передается jq -R, который преобразует всю строку в строку JSON, которая в конечном итоге собирается в окончательный массив. Вместо этого использование printf '{ "add": "%s" }' "${label}" сохранит кавычки (но все равно будет нарушено, если $label содержит неэкранированные символы, поэтому лучше, чтобы jq сам кодировал любой контент в JSON, а не пытался создать его самостоятельно).

pmf 11.06.2024 18:26
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
1
1
82
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Поскольку ваш ключ add статический, я бы передал value только того элемента, который вы хотите добавить, используя правильный ключ в качестве varibale.

Тогда вы можете добавить его, выполнив .. |= { $add } :

jq --arg add "labelValue" '.update.labels |= { $add }' <<< "$data"
Ответ принят как подходящий

Почему бы не сделать все за один вызов jq, используя --args "$@" для передачи всех аргументов в jq и массив $ARGS.positional для ссылки на них:

#!/bin/bash

data='{"update": { "labels": [] } }'

jq '.update.labels += [{add: $ARGS.positional[]}]' --args "$@" <<< "$data" > output.json

Или, если вы позволите jq также сгенерировать исходный документ, на самом деле это всего лишь один вызов:

#!/bin/sh

jq -n '.update.labels = [{add: $ARGS.positional[]}]' --args "$@" > output.json

Обязательно экранируйте кавычки ключ/значение:

for label in "$@"; do
    objJSON=$(echo "{ \"add\": \"$label\" }" | jq -c .)
###       escape here-^----^---^-------^   compact-^
    data=$(echo "$data" | jq --argjson jsonString "$objJSON" '.update.labels += [$jsonString]')
done

Вот скрипт Bash, который обрабатывает добавление новых объектов в массив меток обновлений.

#!/usr/bin/env bash

DEFAULT_OUTPUT_FILENAME=output.txt

# Function to display help
show_help() {
    echo "Usage: $(basename "$0") [options] [label1] [label2] ... [labelN]"
    echo
    echo "This script takes key-value pair arguments and adds them to a JSON document."
    echo
    echo "Options:"
    echo "  -i, --input FILE   Input JSON file to append labels to (default: ${DEFAULT_OUTPUT_FILENAME})."
    echo "  -o, --output FILE  Output to FILE instead of ${DEFAULT_OUTPUT_FILENAME}."
    echo "  -h, --help         Display this help message."
    echo
    echo "Arguments:"
    echo "  labelN        The key-value pair to add to the JSON document."
    echo
    echo "Example:"
    echo "  $(basename "$0") \"label1\" \"label2\" \"label3\""
    echo "  $(basename "$0") -i existing.json -o updated.json \"label1\" \"label2\""
}

# Initialize variables
input_file=${DEFAULT_OUTPUT_FILENAME}
output_file=${DEFAULT_OUTPUT_FILENAME}

# Parse options
while [[ "$1" == -* ]]; do
    case "$1" in
        -i|--input)
            input_file = "$2"
            shift 2
            ;;
        -o|--output)
            output_file = "$2"
            shift 2
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        *)
            echo "Unknown option: $1"
            show_help
            exit 1
            ;;
    esac
done

# Ensure at least one label is provided
if [[ $# -eq 0 ]]; then
    echo "No labels provided. Use -h or --help for usage information."
    exit 1
fi

# Initialize JSON data
if [[ -f "$input_file" ]]; then
    data=$(cat "$input_file")
else
    data='{"update": { "labels": [] } }'
fi

# Iterate over the labels
for label in "$@"; do
    # Create JSON object from the label
    objJSON=$(echo "{ \"add\": \"$label\" }" | jq -c .)
    # Append the JSON object to the labels array
    data=$(echo "$data" | jq --argjson jsonString "$objJSON" '.update.labels += [$jsonString]')
done

# Output the final JSON to a file
echo "$data" > "$output_file"

# Pretty print the JSON
jq --color-output . "$output_file"

Вот использование:

[user@host ~]$ ./json_add.sh --help
Usage: json_add.sh [options] [label1] [label2] ... [labelN]

This script takes key-value pair arguments and adds them to a JSON document.

Options:
  -i, --input FILE   Input JSON file to append labels to (default: output.txt).
  -o, --output FILE  Output to FILE instead of output.txt.
  -h, --help         Display this help message.

Arguments:
  labelN        The key-value pair to add to the JSON document.

Example:
  json_add.sh "label1" "label2" "label3"
  json_add.sh -i existing.json -o updated.json "label1" "label2"

Другие вопросы по теме