yq/upgrading-from-v3.md
2022-01-28 12:50:13 +11:00

237 lines
5.0 KiB
Markdown

# Upgrading from V3
Version 4 of `yq` is quite different from previous versions (and I apologise for that) - however it will be very familiar if you have used `jq` before as it now uses a similar syntax. Most commands that you could do in `v3` are longer in `v4` as a result of having a more expressive syntax language.
Note that `v4` by default now:
* prints all documents of a yaml file.
* prints in color (when outputting to a terminal).
* document separators are printed out by default
## How to do v3 things in v4:
In `v3` yq had seperate commands for reading/writing/deleting and more. In `v4` all these have been embedded into a single expression you specify to either the `eval` command (which runs the expression against each yaml document for each file given in sequence) or the `eval-all` command, which reads all documents of all files, and runs the given expression once.
Many flags from `v3` have been put into the expression language, for instance `stripComments` allowing you to specify which nodes to strip comments from instead of only being able to apply the flag to the entire document.
Lets have a look at the commands for the most common tasks:
### Navigating
v3:
```
yq r sample.yaml 'a.b.c'
```
v4:
```
yq '.a.b.c' sample.yaml
```
### Reading with default value
v3:
```
yq r sample.yaml --defaultValue frog path.not.there
```
v4: (use the [alternative](broken-reference) operator)
```
yq '.path.not.there // "frog"' sample.yaml
```
### Finding nodes
v3:
```bash
yq r sample.yaml 'a.(b.d==cat).f'
```
v4:
```bash
yq '.a | select(.b.d == "cat") | .f' sample.yaml
```
### Recursively match nodes
v3:
```
yq r sample.yaml 'thing.**.name'
```
v4:
```
yq '.thing | .. | select(has("name"))' sample.yaml
```
### Multiple documents
v3:
```bash
yq r -d1 sample.yaml 'b.c'
```
v4 (via the document index operator):
```bash
yq 'select(documentIndex == 1) | .b.c' sample.yml
```
### Updating / writing documents
v3:
```
yq w sample.yaml 'a.b.c' fred
```
v4:
```
yq '.a.b.c = "fred"' sample.yaml
```
### Deleting documents
v3:
```bash
yq d sample.yaml 'a.b.c'
```
v4:
```bash
yq 'del(.a.b.c)' sample.yaml
```
### Merging documents
Like `jq`, merge is done via the multiply operator. You will need to use the eval-all command to load all documents into memory at once, and then use the file operator to select the file nodes to merge.
```bash
yq eval-all 'select(fileIndex == 0) * select(filename == "file2.yaml")' file1.yaml file2.yaml
```
### Prefix yaml
Use the [Create / Collect Into Object ](broken-reference)operator to create a new object with the desired prefix. 
v3:
```
yq p data1.yaml c.d
```
v4:
```
yq '{"c": {"d": . }}' data1.yml
```
### Create new yaml documents
Note that in v4 you can no longer run expressions against an empty file to populate it - because the file is empty, there are no matches for `yq` to run through the expression pipeline - for what it's worth, this is what `jq` does as well. Instead use the `--null-input/-n` flag and pipe out the results to the file you want directly (see example below).
v3:
```
yq n b.c cat
```
v4:
```
yq -n '.b.c = "cat"'
```
### Validate documents
v3:
```
yq validate some.file
```
v4:
```
yq 'true' some.file > /dev/null
```
Note that passing 'true' as the expression saves having to reencode the yaml (only to pipe it to stdout). In v4 you can also do a slightly more sophisticated validation and assert the tag on the root level, so you can ensure the yaml file is a map or array at the top level:
```
yq --exit-status 'tag == "!!map" or tag== "!!seq"' some.file > /dev/null
```
### Comparing yaml files
v3:
```
yq compare --prettyPrint file1.yml file2.yml
```
v4:
In v4 there is no built in compare command, instead it relies on using diff. The downside is longer syntax, the upside is that you can use the full power of diff.
```
diff <(yq -P file1.yml) <(yq -P file2.yml)
```
### Script files
v3 had a script feature that let you run an array of commands specified in a file in one go. The format for this looked like
```yaml
- command: update
path: a.key1
value: things
- command: delete
path: a.ab.key2
```
V4 doesn't have a similar feature, however the fact that you can run multiple operations in a single expression makes it easier to come up with a shell script that does the same thing:
```bash
#!/bin/bash
yq '
.a.key1 = "things" |
del(.a.ab.key2)
' ./examples/data1.yaml
```
### Some new things you can do in v4:
Construct dynamic yaml [maps ](broken-reference)and [arrays ](broken-reference)based on input yaml
Using the [union ](broken-reference)operator, you can run multiple updates in one go and read multiple paths in one go
Fine grain merging of maps using the [multiply](broken-reference) operator
Read and and control yaml metadata better (e.g. [tags](broken-reference), [paths](broken-reference), [document indexes](broken-reference), [anchors and aliases](broken-reference), [comments](broken-reference)).
Work with multiple files (not just for merge)
The underlying expression language is much more powerful than `v3` so expect to see more features soon!
###