问题
I read data from a json file with jq. I wanna append the results into a yaml file, but I dont get it working. I am quite new to shell programming. My goal is to append that "users" to an existing "users"-Array in a yaml file.
This is my json file:
#$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"]
}
]
}
I filter it with that:
cat $DEFAULTS_FILE | jq .users
I have no clue how to convert that json into a yaml.
My expected result should be:
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
I tried to use a second tool called yq
which is similar to jq
and can write yaml files. But I have no positive progress.
EDIT
I know that I can add content to the yaml with that:
yq w -i "my.yml" "users[+]" "some content"
But I dont know how to merge my json into that.
Any help or hint would be nice, thank you in advance...
回答1:
I'm not sure what rules you're using to get to your expected result. It seems like you're randomly applying different rules to how the values are being converted.
As I understand it, scalar values are just output as is (with potential encoding), objects are output as key/value pairs, and array objects are output with a -
for every item. The indentation associates what's part of what.
So based on those rules if you're going to use 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:][])"
)
// .
;
Then to use it, add it to your .jq
file and use it:
$ 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
Here's another variation that aligns the values
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
回答2:
I've used ruby to write my json content into yaml.
As for your example, it can be achieved like this:
cat $DEFAULTS_FILE | jq .users | ruby -ryaml -rjson -e 'puts YAML.dump(JSON.parse(STDIN.read))' > my.yml
回答3:
function yaml_validate {
python -c 'import sys, yaml, json; yaml.safe_load(sys.stdin.read())'
}
function yaml2json {
python -c 'import sys, yaml, json; print(json.dumps(yaml.safe_load(sys.stdin.read())))'
}
function yaml2json_pretty {
python -c 'import sys, yaml, json; print(json.dumps(yaml.safe_load(sys.stdin.read()), indent=2, sort_keys=False))'
}
function json_validate {
python -c 'import sys, yaml, json; json.loads(sys.stdin.read())'
}
function json2yaml {
python -c 'import sys, yaml, json; print(yaml.dump(json.loads(sys.stdin.read())))'
}
More Bash tricks at http://github.com/frgomes/bash-scripts
回答4:
Another oneliner:
python -c 'import yaml, sys; print(yaml.dump(yaml.load(open(sys.argv[1])), default_flow_style=False))' input.json
(exploiting the fact that valid json is also valid yaml)
And yaml to json:
python -c 'import yaml, json, sys; print(json.dumps(yaml.load(open(sys.argv[1])), indent=2))' input.yaml
回答5:
I'v been able to get the result using the following command:
jq -r .users defaultsfile.txt >> users.yaml
The output is in clear yaml format.
来源:https://stackoverflow.com/questions/53315791/how-to-convert-a-json-response-into-yaml-in-bash