2015-11-05 4 views
0

Я пытаюсь изменить вложенные объекты JSON с помощью функции jq <map> в сценарии bash/shell; что-то похожее на this blog entry, но попытка адаптировать примеры здесь к вложенным объектам.Изменить вложенный JSON с помощью jq

Возвращенный JSON должен быть изменен следующим образом:

{ 
    "name": "vendor-module", 
    "dependencies": { 
    "abc": { 
     "from": "[email protected]", 
     "resolved": "https://some.special.url", 
     "version": "2.4.0" 
    }, 
    "acme": { 
     "from": "[email protected]", 
     "resolved": "<CHANGE_THIS>", 
     "version": "1.2.3" 
    } 
    } 
} 

Это будет моя попытка:

modules="`node -pe 'JSON.parse(process.argv[1]).dependencies.$dependency' \ 
    "$(cat $wrapped)"`" 
version="1.2.3" 
resolved="some_url" 

cat OLD.json | 
    jq 'to_entries | 
     map(if .dependencies[0].$module[0].from == "[email protected]$version" 
      then . + {"resolved"}={"$resolved"} 
      else . 
      end 
     ) | 
     from_entries' > NEW.json 

Очевидно, что это не работает. Когда я запускаю сценарий, создается NEW.json, но без изменений или возвращенных ошибок. Если я не нацелен на вложенный объект (например, "name": "vendor-module"), сценарий работает так, как ожидалось. Я уверен, что есть способ сделать это, используя собственные bash и jq .. ?? Любая помощь (с надлежащим побегом) будет с благодарностью оценена.

UPDATE:

Thnx с помощью Charles Duffy's answer, и его предложение использовать sponge, Решение, которое работает хорошо для меня:

jq --arg mod "acme" --arg resolved "Some URL" \ 
    '.dependencies[$mod].resolved |= $resolved' \ 
    OLD.json | sponge OLD.json 
+0

Нужна запятая после «из» для «acme», чтобы это было верно JSON, кстати. –

+0

Waitaminute. У вас есть 'modules' в ваших входных переменных - если вы уже знаете, что вам нужно изменить' acme', а не 'abc', зачем вообще искать' from' и 'version'? –

+0

Typo - Thnx. Я быстро напечатал это в качестве примера - я не хотел загрязнять этот вопрос кучей не относящегося к делу кода. – CelticParser

ответ

0

Для существующих образцов данных, следующие достаточно:

jq --arg mod "acme" \ 
    --arg resolved "some_url" \ 
    '.dependencies[$mod].resolved=$resolved' \ 
    <in.json >out.json 

... для фильтрации по from, by contr ast:

jq --arg new_url "http://new.url/" \ 
    --arg target "[email protected]" \ 
    '.dependencies=(.dependencies 
        | to_entries 
        | map(if(.value.from == $target) 
         then .value.resolved=$new_url 
         else . end) 
        | from_entries)' \ 
    <in.json >out.json 
+0

Работает со следующим редактированием: 'jq --arg mod" acme "--arg resolved" some_url "'.dependencies [$ mod] .resolved = $ resolved' OLD.json> NEW.json' В противном случае' jq' didn (например, THROWS: jq - командный процессор JSON [версия 1.3] Использование: jq [опции] [файл ...] Описание параметров командной строки и Как написать jq-фильтры (и почему вы можете захотеть) см. Справочную страницу jq или онлайн-документацию по адресу http://stedolan.github.com/jq) LOL Thnx! – CelticParser

+0

Очевидной ошибкой было отсутствие продолжения новой строки после второго '-arg'; с учетом этого код в ответе работает для меня при копировании - вклеен точно как есть. –

+0

Это кажется более эффективным: 'jq --arg mod" acme "--arg resolved" Some URL ".dependencies [$ mod] .resolved | = [$ resolved] 'OLD.json | tee OLD.json' Что вы берете? – CelticParser

2

Если вы знаете имя зависимостей, которое хотите обновить, вы можете просто индексировать его.

$ jq --arg dep "$dep" --arg resolved "$resolved" \ 
    '.dependencies[$dep].resolved = $resolved' \ 
    OLD.json > NEW.json 

В противном случае, чтобы изменить зависимость на основе имени (или иного имущества), поиск зависимостей и обновления.

$ jq --arg version "$version" --arg resolved "$resolved" \ 
    '(.dependencies[] | select(.version == $version)).resolved = $resolved' \ 
    OLD.json > NEW.json 
+0

Использование 'select' таким образом (для охвата мутирующей операции) - очень хороший трюк; +1. –

Смежные вопросы