#json #bash #command-line #jq
#json #bash #командная строка #jq
Вопрос:
У меня есть два файла
file1.json
{
"a": "x1",
"b": "y1",
"c": "z1"
}
file2.json
{
"a": "x2",
"b": "y2"
}
Поскольку a amp; b уже существует в file2, я хочу вывести новый объект, содержащий только c. Значения на самом деле не имеют значения.
{
"c": "z1"
}
Я пытался
jq -s '.[0] | to_entries | map(select(.key | in(.[1]) | not)) | from_entries' temp1.json temp2.json
Но я получаю следующую ошибку:
jq: error (at temp2.json:4): Cannot index string with number
Забавная вещь, когда я пытаюсь:
jq -s '.[0] | to_entries | map(select(.key | in({"a": "x2", "b": "y2"}) | not)) | from_entries' file1.json file2.json
Я получаю правильный вывод. Так что просто кажется, что jq обрабатывает.[1] как int? и не как объект json.
Комментарии:
1.
.key |
делает вашу.
строку, например"a"
. Что вы ожидаете"a"[1]
иметь в виду?
Ответ №1:
Этот «хак» — это то, что сделало это для меня до сих пор. Мне любопытно, есть ли что-нибудь лучше.
jq -s '. as $input | $input[0] | to_entries | map(select(.key | in($input[1]) | not)) | from_entries' temp1.json temp2.json
Ответ №2:
Вот простой подход, использующий reduce
:
jq -n --argfile one file1.json --argfile two file2.json '
reduce ($two|keys_unsorted)[] as $k ($one; delpaths([[$k]]))'
И вот более эффективный фильтр, который все еще использует delpaths
:
$one | delpaths($two|keys_unsorted|map([.]))
Ответ №3:
Вот общая функция для выполнения вычитания объекта:
# remove from $x all the keys that occur in $y
def minus($x; $y):
((($x $y)|to_entries) - ($y|to_entries))
| from_entries;
Это можно использовать для решения проблемы различными способами, например, с помощью вызова:
jq -n -f program.jq file1.json file2.json
где program.jq содержит указанное выше определение, за которым следует:
minus(input; input)