Как преобразовать ответ JSON в YAML в Bash - PullRequest
0 голосов
/ 15 ноября 2018

Я читаю данные из файла json с помощью jq. Я хочу добавить результаты в файл yaml, но у меня не получается. Я довольно новичок в программировании оболочки. Моя цель - добавить эти «пользователи» к существующему массиву «пользователи» в файле yaml.

Это мой файл json:

#$DEFAULTS_FILE

{"users":
  [
    {"name":"pi",
      "gecos": "Hypriot Pirate",
      "sudo":"ALL=(ALL) NOPASSWD:ALL",
      "shell": "/bin/bash",
      "groups":"users,docker,video",
      "plain_text_passwd":"pi",
      "lock_passwd":"false",
      "ssh_pwauth":"true",
      "chpasswd": {"expire": false}
    },
    {"name":"admin",
      "gecos": "Hypriot Pirate",
      "sudo":"ALL=(ALL) NOPASSWD:ALL",
      "shell": "/bin/bash",
      "primary-group": "users",
      "groups":"users,docker,adm,dialout,audio,plugdev,netdev,video",
      "ssh-import-id":"None",
      "plain_text_passwd":"pi",
      "lock_passwd":"true",
      "ssh_pwauth":"true",
      "chpasswd": "{expire: false}",
      "ssh-authorized-keys": ["ssh-rsa abcdefg1234567890 YOUR_KEY@YOURHOST.local"]
    }
  ]
  }

Я фильтрую это так:

cat $DEFAULTS_FILE | jq .users

Понятия не имею, как преобразовать этот json в yaml.

Мой ожидаемый результат должен быть:

users:
  - name:                pi
    gecos:               "Hypriot Pirate"
    sudo:                ALL=(ALL) NOPASSWD:ALL
    shell:               /bin/bash
    groups:              users,docker,video
    plain_text_passwd:   pi
    lock_passwd:         false
    ssh_pwauth:          true
    chpasswd: { expire:  false }
  - name:                admin
    primary-group:       users
    shell:               /bin/bash
    sudo:                ALL=(ALL) NOPASSWD:ALL
    groups:              users,docker,adm,dialout,audio,plugdev,netdev,video
    ssh-import-id:       None

Я попытался использовать второй инструмент под названием yq, который похож на jq и может записывать файлы yaml. Но у меня нет положительного прогресса.

EDIT

Я знаю, что могу добавить контент в yaml следующим образом:

yq w -i "my.yml" "users[+]" "some content"

Но я не знаю, как слить мой JSON в это.

Любая помощь или подсказка были бы хорошими, заранее спасибо ...

Ответы [ 2 ]

0 голосов
/ 16 ноября 2018

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

Насколько я понимаю, скалярные значения просто выводятся как есть (с потенциальным кодированием), объекты выводятся в виде пар ключ / значение, а объекты массива выводятся с - для каждого элемента. Отступ связывает то, что является частью чего.

Итак, основываясь на этих правилах, если вы собираетесь использовать jq:

def yamlify:
    (objects | to_entries[] | (.value | type) as $type |
        if $type == "array" then
            "\(.key):", (.value | yamlify)
        elif $type == "object" then
            "\(.key):", "    \(.value | yamlify)"
        else
            "\(.key):\t\(.value)"
        end
    )
    // (arrays | select(length > 0)[] | [yamlify] |
        "  - \(.[0])", "    \(.[1:][])"
    )
    // .
    ;

Затем, чтобы использовать его, добавьте его в файл .jq и используйте его:

$ jq -r yamlify input.json
users:
  - name:       pi
    gecos:      Hypriot Pirate
    sudo:       ALL=(ALL) NOPASSWD:ALL
    shell:      /bin/bash
    groups:     users,docker,video
    plain_text_passwd:  pi
    lock_passwd:        false
    ssh_pwauth: true
    chpasswd:
        expire: false
  - name:       admin
    gecos:      Hypriot Pirate
    sudo:       ALL=(ALL) NOPASSWD:ALL
    shell:      /bin/bash
    primary-group:      users
    groups:     users,docker,adm,dialout,audio,plugdev,netdev,video
    ssh-import-id:      None
    plain_text_passwd:  pi
    lock_passwd:        true
    ssh_pwauth: true
    chpasswd:   {expire: false}
    ssh-authorized-keys:
      - ssh-rsa abcdefg1234567890 YOUR_KEY@YOURHOST.local

Вот еще один вариант, который выравнивает значения

def yamlify2:
    (objects | to_entries | (map(.key | length) | max + 2) as $w |
        .[] | (.value | type) as $type |
        if $type == "array" then
            "\(.key):", (.value | yamlify2)
        elif $type == "object" then
            "\(.key):", "    \(.value | yamlify2)"
        else
            "\(.key):\(" " * (.key | $w - length))\(.value)"
        end
    )
    // (arrays | select(length > 0)[] | [yamlify2] |
        "  - \(.[0])", "    \(.[1:][])"
    )
    // .
    ;
$ jq -r yamlify2 input.json
users:
  - name:               pi
    gecos:              Hypriot Pirate
    sudo:               ALL=(ALL) NOPASSWD:ALL
    shell:              /bin/bash
    groups:             users,docker,video
    plain_text_passwd:  pi
    lock_passwd:        false
    ssh_pwauth:         true
    chpasswd:
        expire:  false
  - name:                 admin
    gecos:                Hypriot Pirate
    sudo:                 ALL=(ALL) NOPASSWD:ALL
    shell:                /bin/bash
    primary-group:        users
    groups:               users,docker,adm,dialout,audio,plugdev,netdev,video
    ssh-import-id:        None
    plain_text_passwd:    pi
    lock_passwd:          true
    ssh_pwauth:           true
    chpasswd:             {expire: false}
    ssh-authorized-keys:
      - ssh-rsa abcdefg1234567890 YOUR_KEY@YOURHOST.local
0 голосов
/ 15 ноября 2018

В итоге я установил гем и использовал ruby:

gem install deep_merge (https://github.com/danielsdeleo/deep_merge)

Вот мой подход:

#!/usr/bin/env ruby
#
require 'json'
require 'yaml'
require 'deep_merge/rails_compat'

json_input_file = ARGF.argv[0]
yaml_output_file = ARGF.argv[1]
scope = ARGF.argv[2]

json = File.read(json_input_file)
yaml = File.read(yaml_output_file)

json_data = JSON.parse(json)
scoped_result = json_data[scope]

old_values_hash = YAML.load(File.read(yaml_output_file))
result = YAML.parse(yaml)
merged = old_values_hash.deeper_merge scoped_result

File.write(yaml_output_file, merged.to_yaml)

Затем его можно использовать для чтения определенного scoped_value из файла json.

jsonyaml.sh $JSON_FILE $YAML_TARGET "my_scope_to_add"

...