mirror of
https://github.com/mikefarah/yq.git
synced 2026-08-24 16:39:58 +08:00
Compare commits
60
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75fffc17e1 | ||
|
|
e1b5e90adf | ||
|
|
6374098cdc | ||
|
|
b35893d783 | ||
|
|
4b2b47af48 | ||
|
|
a5f6a80cf6 | ||
|
|
a9c3617b4f | ||
|
|
4d4bd5114d | ||
|
|
bfaafa66f9 | ||
|
|
26356ff4be | ||
|
|
06e944dcb6 | ||
|
|
2891c6948d | ||
|
|
703418d0c4 | ||
|
|
75960c6484 | ||
|
|
5ac3c57510 | ||
|
|
926a68181b | ||
|
|
1f367ac200 | ||
|
|
de38abb121 | ||
|
|
d00153de71 | ||
|
|
992fe066aa | ||
|
|
b80080a26d | ||
|
|
0afb59c65e | ||
|
|
535799462f | ||
|
|
77204551ab | ||
|
|
772d369058 | ||
|
|
9b7c80a76b | ||
|
|
a6fc7aa881 | ||
|
|
6f27cb93d1 | ||
|
|
b2a93930d0 | ||
|
|
dedd1ca892 | ||
|
|
01b4917f26 | ||
|
|
25e374f4ee | ||
|
|
3ba728d40c | ||
|
|
8761920f58 | ||
|
|
394be5c65a | ||
|
|
4ec533bc1b | ||
|
|
fc276ff450 | ||
|
|
c3d815998a | ||
|
|
71242b0c8e | ||
|
|
a9e7f669d0 | ||
|
|
8195ff8b9b | ||
|
|
9b1a7bf451 | ||
|
|
9b66e0a094 | ||
|
|
6e33132de9 | ||
|
|
a6c79f3410 | ||
|
|
50df792e49 | ||
|
|
6f24e878aa | ||
|
|
a0ba208669 | ||
|
|
d5b0154747 | ||
|
|
7d2ddc1cde | ||
|
|
02252e8e69 | ||
|
|
2526b03d67 | ||
|
|
e347090571 | ||
|
|
f8bcaca4c9 | ||
|
|
de0716e875 | ||
|
|
21cdbab0d7 | ||
|
|
1fba46f2f7 | ||
|
|
dfe4308304 | ||
|
|
8c94a96ee0 | ||
|
|
ec8ef312ef |
@@ -26,7 +26,7 @@ country: Australia
|
||||
And we run a command:
|
||||
|
||||
```bash
|
||||
yq eval 'predictWeatherOf(.country)'
|
||||
yq 'predictWeatherOf(.country)'
|
||||
```
|
||||
|
||||
it could output
|
||||
|
||||
@@ -25,6 +25,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Check the build
|
||||
shell: bash -l {0}
|
||||
run: |
|
||||
export PATH=${PATH}:`go env GOPATH`/bin
|
||||
scripts/devtools.sh
|
||||
|
||||
@@ -18,6 +18,14 @@ linters:
|
||||
- revive
|
||||
- unconvert
|
||||
- unparam
|
||||
linters-settings:
|
||||
depguard:
|
||||
list-type: blacklist
|
||||
include-go-root: true
|
||||
packages:
|
||||
- io/ioutil
|
||||
packages-with-error-message:
|
||||
- io/ioutil: "The 'io/ioutil' package is deprecated. Use corresponding 'os' or 'io' functions instead."
|
||||
issues:
|
||||
exclude-rules:
|
||||
- linters:
|
||||
|
||||
@@ -3,40 +3,67 @@
|
||||
   
|
||||
|
||||
|
||||
a lightweight and portable command-line YAML processor. `yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml files as well as json. It doesn't yet support everything `jq` does - but it does support the most common operations and functions, and more is being added continuously.
|
||||
a lightweight and portable command-line YAML, JSON and XML processor. `yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml files as well as json and xml. It doesn't yet support everything `jq` does - but it does support the most common operations and functions, and more is being added continuously.
|
||||
|
||||
yq is written in go - so you can download a dependency free binary for your platform and you are good to go! If you prefer there are a variety of package managers that can be used as well as Docker and Podman, all listed below.
|
||||
|
||||
## Notice for v4.x versions prior to 4.18.1
|
||||
Since 4.18.1, yq's 'eval/e' command is the _default_ command and no longers needs to be specified.
|
||||
|
||||
Older versions will still need to specify 'eval/e'.
|
||||
|
||||
Similarly, '-' is no longer required as a filename to read from STDIN (unless reading from multiple files).
|
||||
|
||||
TLDR:
|
||||
|
||||
Prior to 4.18.1
|
||||
```bash
|
||||
cat file.yaml | yq e '.cool' -
|
||||
```
|
||||
|
||||
4.18+
|
||||
```bash
|
||||
cat file.yaml | yq '.cool'
|
||||
```
|
||||
|
||||
When merging multiple files together, `eval-all/ea` is still required to tell `yq` to run the expression against all the document at once.
|
||||
|
||||
## Quick Usage Guide
|
||||
|
||||
|
||||
|
||||
|
||||
Read a value:
|
||||
```bash
|
||||
yq e '.a.b[0].c' file.yaml
|
||||
yq '.a.b[0].c' file.yaml
|
||||
```
|
||||
|
||||
Pipe from STDIN:
|
||||
```bash
|
||||
cat file.yaml | yq e '.a.b[0].c' -
|
||||
cat file.yaml | yq '.a.b[0].c'
|
||||
```
|
||||
|
||||
Update a yaml file, inplace
|
||||
```bash
|
||||
yq e -i '.a.b[0].c = "cool"' file.yaml
|
||||
yq -i '.a.b[0].c = "cool"' file.yaml
|
||||
```
|
||||
|
||||
Update using environment variables
|
||||
```bash
|
||||
NAME=mike yq e -i '.a.b[0].c = strenv(NAME)' file.yaml
|
||||
NAME=mike yq -i '.a.b[0].c = strenv(NAME)' file.yaml
|
||||
```
|
||||
|
||||
Merge multiple files
|
||||
```
|
||||
```bash
|
||||
# note the use of `ea` to evaluate all the files at once
|
||||
# instead of in sequence
|
||||
yq ea '. as $item ireduce ({}; . * $item )' path/to/*.yml
|
||||
```
|
||||
|
||||
|
||||
Multiple updates to a yaml file
|
||||
```bash
|
||||
yq e -i '
|
||||
yq -i '
|
||||
.a.b[0].c = "cool" |
|
||||
.x.y.z = "foobar" |
|
||||
.person.name = strenv(NAME)
|
||||
@@ -82,30 +109,32 @@ snap install yq
|
||||
`yq` installs with [_strict confinement_](https://docs.snapcraft.io/snap-confinement/6233) in snap, this means it doesn't have direct access to root files. To read root files you can:
|
||||
|
||||
```
|
||||
sudo cat /etc/myfile | yq e '.a.path' -
|
||||
sudo cat /etc/myfile | yq '.a.path'
|
||||
```
|
||||
|
||||
And to write to a root file you can either use [sponge](https://linux.die.net/man/1/sponge):
|
||||
```
|
||||
sudo cat /etc/myfile | yq e '.a.path = "value"' - | sudo sponge /etc/myfile
|
||||
sudo cat /etc/myfile | yq '.a.path = "value"' | sudo sponge /etc/myfile
|
||||
```
|
||||
or write to a temporary file:
|
||||
```
|
||||
sudo cat /etc/myfile | yq e '.a.path = "value"' | sudo tee /etc/myfile.tmp
|
||||
sudo cat /etc/myfile | yq '.a.path = "value"' | sudo tee /etc/myfile.tmp
|
||||
sudo mv /etc/myfile.tmp /etc/myfile
|
||||
rm /etc/myfile.tmp
|
||||
```
|
||||
|
||||
### Run with Docker or Podman
|
||||
|
||||
#### Oneshot use:
|
||||
|
||||
```bash
|
||||
docker run --rm -v "${PWD}":/workdir mikefarah/yq <command> [flags] [expression ]FILE...
|
||||
docker run --rm -v "${PWD}":/workdir mikefarah/yq [command] [flags] [expression ]FILE...
|
||||
```
|
||||
|
||||
Note that you can run `yq` in docker without network access and other privileges if you desire,
|
||||
namely `--security-opt=no-new-privileges --cap-drop all --network none`.
|
||||
|
||||
```bash
|
||||
podman run --rm -v "${PWD}":/workdir mikefarah/yq <command> [flags] [expression ]FILE...
|
||||
podman run --rm -v "${PWD}":/workdir mikefarah/yq [command] [flags] [expression ]FILE...
|
||||
```
|
||||
|
||||
#### Pipe in via STDIN:
|
||||
@@ -113,11 +142,11 @@ podman run --rm -v "${PWD}":/workdir mikefarah/yq <command> [flags] [expression
|
||||
You'll need to pass the `-i\--interactive` flag to docker:
|
||||
|
||||
```bash
|
||||
cat myfile.yml | docker run -i --rm mikefarah/yq e . -
|
||||
cat myfile.yml | docker run -i --rm mikefarah/yq '.this.thing'
|
||||
```
|
||||
|
||||
```bash
|
||||
cat myfile.yml | podman run -i --rm mikefarah/yq e . -
|
||||
cat myfile.yml | podman run -i --rm mikefarah/yq '.this.thing'
|
||||
```
|
||||
|
||||
#### Run commands interactively:
|
||||
@@ -164,16 +193,28 @@ Or, in your Dockerfile:
|
||||
FROM mikefarah/yq
|
||||
|
||||
USER root
|
||||
RUN apk add bash
|
||||
RUN apk add --no-cache bash
|
||||
USER yq
|
||||
```
|
||||
|
||||
#### Missing timezone data
|
||||
By default, the alpine image yq uses does not include timezone data. If you'd like to use the `tz` operator, you'll need to include this data:
|
||||
|
||||
```
|
||||
FROM mikefarah/yq
|
||||
|
||||
USER root
|
||||
RUN apk add --no-cache tzdata
|
||||
USER yq
|
||||
```
|
||||
|
||||
|
||||
### GitHub Action
|
||||
```
|
||||
- name: Set foobar to cool
|
||||
uses: mikefarah/yq@master
|
||||
with:
|
||||
cmd: yq eval -i '.foo.bar = "cool"' 'config.yml'
|
||||
cmd: yq -i '.foo.bar = "cool"' 'config.yml'
|
||||
```
|
||||
|
||||
See https://mikefarah.gitbook.io/yq/usage/github-action for more.
|
||||
@@ -238,19 +279,21 @@ Supported by @rmescandon (https://launchpad.net/~rmescandon/+archive/ubuntu/yq)
|
||||
## Features
|
||||
- [Detailed documentation with many examples](https://mikefarah.gitbook.io/yq/)
|
||||
- Written in portable go, so you can download a lovely dependency free binary
|
||||
- Uses similar syntax as `jq` but works with YAML and JSON files
|
||||
- Uses similar syntax as `jq` but works with YAML, [JSON](https://mikefarah.gitbook.io/yq/usage/convert) and [XML](https://mikefarah.gitbook.io/yq/usage/xml) files
|
||||
- Fully supports multi document yaml files
|
||||
- Supports yaml [front matter](https://mikefarah.gitbook.io/yq/usage/front-matter) blocks (e.g. jekyll/assemble)
|
||||
- Colorized yaml output
|
||||
- [Deeply traverse yaml](https://mikefarah.gitbook.io/yq/operators/traverse-read)
|
||||
- [Sort yaml by keys](https://mikefarah.gitbook.io/yq/operators/sort-keys)
|
||||
- [Deeply data structures](https://mikefarah.gitbook.io/yq/operators/traverse-read)
|
||||
- [Sort keys](https://mikefarah.gitbook.io/yq/operators/sort-keys)
|
||||
- Manipulate yaml [comments](https://mikefarah.gitbook.io/yq/operators/comment-operators), [styling](https://mikefarah.gitbook.io/yq/operators/style), [tags](https://mikefarah.gitbook.io/yq/operators/tag) and [anchors and aliases](https://mikefarah.gitbook.io/yq/operators/anchor-and-alias-operators).
|
||||
- [Update yaml inplace](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate#flags)
|
||||
- [Update inplace](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate#flags)
|
||||
- [Complex expressions to select and update](https://mikefarah.gitbook.io/yq/operators/select#select-and-update-matching-values-in-map)
|
||||
- Keeps yaml formatting and comments when updating (though there are issues with whitespace)
|
||||
- [Load content from other files](https://mikefarah.gitbook.io/yq/operators/load)
|
||||
- [Convert to/from json](https://mikefarah.gitbook.io/yq/v/v4.x/usage/convert)
|
||||
- [Convert to properties](https://mikefarah.gitbook.io/yq/v/v4.x/usage/properties)
|
||||
- [Convert to/from xml](https://mikefarah.gitbook.io/yq/v/v4.x/usage/xml)
|
||||
- [Convert to/from properties](https://mikefarah.gitbook.io/yq/v/v4.x/usage/properties)
|
||||
- [Convert to csv/tsv](https://mikefarah.gitbook.io/yq/usage/csv-tsv)
|
||||
- [Pipe data in by using '-'](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate)
|
||||
- [General shell completion scripts (bash/zsh/fish/powershell)](https://mikefarah.gitbook.io/yq/v/v4.x/commands/shell-completion)
|
||||
- [Reduce](https://mikefarah.gitbook.io/yq/operators/reduce) to merge multiple files or sum an array or other fancy things.
|
||||
@@ -265,28 +308,41 @@ Usage:
|
||||
yq [flags]
|
||||
yq [command]
|
||||
|
||||
Examples:
|
||||
|
||||
# yq defaults to 'eval' command if no command is specified. See "yq eval --help" for more examples.
|
||||
cat myfile.yml | yq '.stuff' # outputs the data at the "stuff" node from "myfile.yml"
|
||||
|
||||
yq -i '.stuff = "foo"' myfile.yml # update myfile.yml inplace
|
||||
|
||||
|
||||
Available Commands:
|
||||
eval Apply the expression to each document in each yaml file in sequence
|
||||
completion Generate the autocompletion script for the specified shell
|
||||
eval (default) Apply the expression to each document in each yaml file in sequence
|
||||
eval-all Loads _all_ yaml documents of _all_ yaml files and runs expression once
|
||||
help Help about any command
|
||||
shell-completion Generate completion script
|
||||
|
||||
Flags:
|
||||
-C, --colors force print with colors
|
||||
-e, --exit-status set exit status if there are no matches or null or false is returned
|
||||
-f, --front-matter string (extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact
|
||||
--header-preprocess Slurp any header comments and seperators before processing expression. This is a workaround for go-yaml to persist header content (default true)
|
||||
-h, --help help for yq
|
||||
-I, --indent int sets indent level for output (default 2)
|
||||
-i, --inplace update the yaml file inplace of first yaml file given.
|
||||
-M, --no-colors force print with no colors
|
||||
-N, --no-doc Don't print document separators (---)
|
||||
-n, --null-input Don't read input, simply evaluate the expression given. Useful for creating yaml docs from scratch.
|
||||
-o, --output-format string [yaml|y|json|j|props|p] output format type. (default "yaml")
|
||||
-P, --prettyPrint pretty print, shorthand for '... style = ""'
|
||||
--unwrapScalar unwrap scalar, print the value with no quotes, colors or comments (default true)
|
||||
-v, --verbose verbose mode
|
||||
-V, --version Print version information and quit
|
||||
-C, --colors force print with colors
|
||||
-e, --exit-status set exit status if there are no matches or null or false is returned
|
||||
-f, --front-matter string (extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact
|
||||
--header-preprocess Slurp any header comments and separators before processing expression. (default true)
|
||||
-h, --help help for yq
|
||||
-I, --indent int sets indent level for output (default 2)
|
||||
-i, --inplace update the file inplace of first file given.
|
||||
-p, --input-format string [yaml|y|xml|x] parse format for input. Note that json is a subset of yaml. (default "yaml")
|
||||
-M, --no-colors force print with no colors
|
||||
-N, --no-doc Don't print document separators (---)
|
||||
-n, --null-input Don't read input, simply evaluate the expression given. Useful for creating docs from scratch.
|
||||
-o, --output-format string [yaml|y|json|j|props|p|xml|x] output format type. (default "yaml")
|
||||
-P, --prettyPrint pretty print, shorthand for '... style = ""'
|
||||
-s, --split-exp string print each result (or doc) into a file named (exp). [exp] argument must return a string. You can use $index in the expression as the result counter.
|
||||
--unwrapScalar unwrap scalar, print the value with no quotes, colors or comments (default true)
|
||||
-v, --verbose verbose mode
|
||||
-V, --version Print version information and quit
|
||||
--xml-attribute-prefix string prefix for xml attributes (default "+")
|
||||
--xml-content-name string name for xml content (if no attribute name is present). (default "+content")
|
||||
|
||||
Use "yq [command] --help" for more information about a command.
|
||||
```
|
||||
|
||||
+152
-2
@@ -1,12 +1,147 @@
|
||||
#!/bin/bash
|
||||
|
||||
setUp() {
|
||||
rm test*.yml || true
|
||||
rm test*.yml 2>/dev/null || true
|
||||
rm .xyz 2>/dev/null || true
|
||||
}
|
||||
|
||||
testBasicEvalRoundTrip() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
X=$(./yq '.a' test.yml)
|
||||
assertEquals 123 "$X"
|
||||
}
|
||||
|
||||
testBasicPipeWithDot() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
X=$(cat test.yml | ./yq '.')
|
||||
assertEquals "a: 123" "$X"
|
||||
}
|
||||
|
||||
testBasicExpressionMatchesFileName() {
|
||||
./yq -n ".xyz = 123" > test.yml
|
||||
touch .xyz
|
||||
|
||||
X=$(./yq --expression '.xyz' test.yml)
|
||||
assertEquals "123" "$X"
|
||||
|
||||
X=$(./yq ea --expression '.xyz' test.yml)
|
||||
assertEquals "123" "$X"
|
||||
|
||||
}
|
||||
|
||||
testBasicGitHubAction() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
X=$(cat /dev/null | ./yq test.yml)
|
||||
assertEquals "a: 123" "$X"
|
||||
|
||||
X=$(cat /dev/null | ./yq e test.yml)
|
||||
assertEquals "a: 123" "$X"
|
||||
|
||||
X=$(cat /dev/null | ./yq ea test.yml)
|
||||
assertEquals "a: 123" "$X"
|
||||
}
|
||||
|
||||
testBasicGitHubActionWithExpression() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
X=$(cat /dev/null | ./yq '.a' test.yml)
|
||||
assertEquals "123" "$X"
|
||||
|
||||
X=$(cat /dev/null | ./yq e '.a' test.yml)
|
||||
assertEquals "123" "$X"
|
||||
|
||||
X=$(cat /dev/null | ./yq ea '.a' test.yml)
|
||||
assertEquals "123" "$X"
|
||||
}
|
||||
|
||||
|
||||
testBasicEvalAllAllFiles() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
./yq -n ".a = 124" > test2.yml
|
||||
X=$(./yq ea test.yml test2.yml)
|
||||
Y=$(./yq e '.' test.yml test2.yml)
|
||||
assertEquals "$Y" "$X"
|
||||
}
|
||||
|
||||
testBasicCatWithFilesNoDash() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
./yq -n ".a = 124" > test2.yml
|
||||
X=$(cat test.yml | ./yq test2.yml)
|
||||
Y=$(./yq e '.' test2.yml test.yml)
|
||||
assertEquals "$Y" "$X"
|
||||
}
|
||||
|
||||
testBasicEvalAllCatWithFilesNoDash() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
./yq -n ".a = 124" > test2.yml
|
||||
X=$(cat test.yml | ./yq ea test2.yml)
|
||||
Y=$(./yq e '.' test2.yml test.yml)
|
||||
assertEquals "$Y" "$X"
|
||||
}
|
||||
|
||||
testBasicCatWithFilesNoDashWithExp() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
./yq -n ".a = 124" > test2.yml
|
||||
X=$(cat test.yml | ./yq '.a' test2.yml)
|
||||
Y=$(./yq e '.a' test2.yml test.yml)
|
||||
assertEquals "$Y" "$X"
|
||||
}
|
||||
|
||||
testBasicEvalAllCatWithFilesNoDashWithExp() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
./yq -n ".a = 124" > test2.yml
|
||||
X=$(cat test.yml | ./yq ea '.a' test2.yml)
|
||||
Y=$(./yq e '.a' test2.yml test.yml)
|
||||
assertEquals "$Y" "$X"
|
||||
}
|
||||
|
||||
|
||||
testBasicStdInWithFiles() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
./yq -n ".a = 124" > test2.yml
|
||||
X=$(cat test.yml | ./yq - test2.yml)
|
||||
Y=$(./yq e '.' test.yml test2.yml)
|
||||
assertEquals "$Y" "$X"
|
||||
}
|
||||
|
||||
testBasicEvalAllStdInWithFiles() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
./yq -n ".a = 124" > test2.yml
|
||||
X=$(cat test.yml | ./yq ea - test2.yml)
|
||||
Y=$(./yq e '.' test.yml test2.yml)
|
||||
assertEquals "$Y" "$X"
|
||||
}
|
||||
|
||||
testBasicStdInWithFilesReverse() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
./yq -n ".a = 124" > test2.yml
|
||||
X=$(cat test.yml | ./yq test2.yml -)
|
||||
Y=$(./yq e '.' test2.yml test.yml)
|
||||
assertEquals "$Y" "$X"
|
||||
}
|
||||
|
||||
testBasicEvalAllStdInWithFilesReverse() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
./yq -n ".a = 124" > test2.yml
|
||||
X=$(cat test.yml | ./yq ea test2.yml -)
|
||||
Y=$(./yq e '.' test2.yml test.yml)
|
||||
assertEquals "$Y" "$X"
|
||||
}
|
||||
|
||||
testBasicEvalRoundTripNoEval() {
|
||||
./yq -n ".a = 123" > test.yml
|
||||
X=$(./yq '.a' test.yml)
|
||||
assertEquals 123 "$X"
|
||||
}
|
||||
|
||||
testBasicStdInWithOneArg() {
|
||||
./yq e -n ".a = 123" > test.yml
|
||||
X=$(./yq e '.a' test.yml)
|
||||
X=$(cat test.yml | ./yq e ".a")
|
||||
assertEquals 123 "$X"
|
||||
|
||||
X=$(cat test.yml | ./yq ea ".a")
|
||||
assertEquals 123 "$X"
|
||||
|
||||
X=$(cat test.yml | ./yq ".a")
|
||||
assertEquals 123 "$X"
|
||||
}
|
||||
|
||||
@@ -19,6 +154,15 @@ EOL
|
||||
assertEquals "10" "$X"
|
||||
}
|
||||
|
||||
testBasicUpdateInPlaceSequenceNoEval() {
|
||||
cat >test.yml <<EOL
|
||||
a: 0
|
||||
EOL
|
||||
./yq -i ".a = 10" test.yml
|
||||
X=$(./yq '.a' test.yml)
|
||||
assertEquals "10" "$X"
|
||||
}
|
||||
|
||||
testBasicUpdateInPlaceSequenceEvalAll() {
|
||||
cat >test.yml <<EOL
|
||||
a: 0
|
||||
@@ -40,6 +184,12 @@ testBasicExitStatus() {
|
||||
assertEquals 1 "$?"
|
||||
}
|
||||
|
||||
testBasicExitStatusNoEval() {
|
||||
echo "a: cat" > test.yml
|
||||
X=$(./yq -e '.z' test.yml 2&>/dev/null)
|
||||
assertEquals 1 "$?"
|
||||
}
|
||||
|
||||
testBasicExtractFieldWithSeperator() {
|
||||
cat >test.yml <<EOL
|
||||
---
|
||||
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
testCompletionRuns() {
|
||||
result=$(./yq __complete "" 2>&1)
|
||||
assertEquals 0 $?
|
||||
assertContains "$result" "Completion ended with directive:"
|
||||
}
|
||||
|
||||
source ./scripts/shunit2
|
||||
@@ -1,7 +1,43 @@
|
||||
#!/bin/bash
|
||||
|
||||
setUp() {
|
||||
rm test*.yml || true
|
||||
rm test*.yml 2>/dev/null || true
|
||||
rm test*.properties 2>/dev/null || true
|
||||
rm test*.xml 2>/dev/null || true
|
||||
}
|
||||
|
||||
testInputProperties() {
|
||||
cat >test.properties <<EOL
|
||||
mike.things = hello
|
||||
EOL
|
||||
|
||||
read -r -d '' expected << EOM
|
||||
mike:
|
||||
things: hello
|
||||
EOM
|
||||
|
||||
X=$(./yq e -p=props test.properties)
|
||||
assertEquals "$expected" "$X"
|
||||
|
||||
X=$(./yq ea -p=props test.properties)
|
||||
assertEquals "$expected" "$X"
|
||||
}
|
||||
|
||||
testInputPropertiesGitHubAction() {
|
||||
cat >test.properties <<EOL
|
||||
mike.things = hello
|
||||
EOL
|
||||
|
||||
read -r -d '' expected << EOM
|
||||
mike:
|
||||
things: hello
|
||||
EOM
|
||||
|
||||
X=$(cat /dev/null | ./yq e -p=props test.properties)
|
||||
assertEquals "$expected" "$X"
|
||||
|
||||
X=$(cat /dev/null | ./yq ea -p=props test.properties)
|
||||
assertEquals "$expected" "$X"
|
||||
}
|
||||
|
||||
testInputXml() {
|
||||
@@ -22,4 +58,22 @@ EOM
|
||||
assertEquals "$expected" "$X"
|
||||
}
|
||||
|
||||
testInputXmlGithubAction() {
|
||||
cat >test.yml <<EOL
|
||||
<cat legs="4">BiBi</cat>
|
||||
EOL
|
||||
|
||||
read -r -d '' expected << EOM
|
||||
cat:
|
||||
+content: BiBi
|
||||
+legs: "4"
|
||||
EOM
|
||||
|
||||
X=$(cat /dev/null | ./yq e -p=xml test.yml)
|
||||
assertEquals "$expected" "$X"
|
||||
|
||||
X=$(cat /dev/null | ./yq ea -p=xml test.yml)
|
||||
assertEquals "$expected" "$X"
|
||||
}
|
||||
|
||||
source ./scripts/shunit2
|
||||
@@ -142,4 +142,25 @@ EOM
|
||||
assertEquals "$expected" "$X"
|
||||
}
|
||||
|
||||
testOutputXmComplex() {
|
||||
cat >test.yml <<EOL
|
||||
a: {b: {c: ["cat", "dog"], +f: meow}}
|
||||
EOL
|
||||
|
||||
read -r -d '' expected << EOM
|
||||
<a>
|
||||
<b f="meow">
|
||||
<c>cat</c>
|
||||
<c>dog</c>
|
||||
</b>
|
||||
</a>
|
||||
EOM
|
||||
|
||||
X=$(./yq e --output-format=x test.yml)
|
||||
assertEquals "$expected" "$X"
|
||||
|
||||
X=$(./yq ea --output-format=x test.yml)
|
||||
assertEquals "$expected" "$X"
|
||||
}
|
||||
|
||||
source ./scripts/shunit2
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
|
||||
setUp() {
|
||||
rm test*.yml || true
|
||||
cat >test.yml <<EOL
|
||||
a: frog
|
||||
EOL
|
||||
}
|
||||
|
||||
testPipeViaCatWithParam() {
|
||||
X=$(cat test.yml | ./yq '.a')
|
||||
assertEquals "frog" "$X"
|
||||
}
|
||||
|
||||
testPipeViaCatWithParamEval() {
|
||||
X=$(cat test.yml | ./yq e '.a')
|
||||
assertEquals "frog" "$X"
|
||||
}
|
||||
|
||||
testPipeViaCatWithParamEvalAll() {
|
||||
X=$(cat test.yml | ./yq ea '.a')
|
||||
assertEquals "frog" "$X"
|
||||
}
|
||||
|
||||
testPipeViaCatNoParam() {
|
||||
X=$(cat test.yml | ./yq)
|
||||
assertEquals "a: frog" "$X"
|
||||
}
|
||||
|
||||
testPipeViaCatNoParamEval() {
|
||||
X=$(cat test.yml | ./yq e)
|
||||
assertEquals "a: frog" "$X"
|
||||
}
|
||||
|
||||
testPipeViaCatNoParamEvalAll() {
|
||||
X=$(cat test.yml | ./yq ea)
|
||||
assertEquals "a: frog" "$X"
|
||||
}
|
||||
|
||||
testPipeViaFileishWithParam() {
|
||||
X=$(./yq '.a' < test.yml)
|
||||
assertEquals "frog" "$X"
|
||||
}
|
||||
|
||||
testPipeViaFileishWithParamEval() {
|
||||
X=$(./yq e '.a' < test.yml)
|
||||
assertEquals "frog" "$X"
|
||||
}
|
||||
|
||||
testPipeViaFileishWithParamEvalAll() {
|
||||
X=$(./yq ea '.a' < test.yml)
|
||||
assertEquals "frog" "$X"
|
||||
}
|
||||
|
||||
testPipeViaFileishNoParam() {
|
||||
X=$(./yq < test.yml)
|
||||
assertEquals "a: frog" "$X"
|
||||
}
|
||||
|
||||
testPipeViaFileishNoParamEval() {
|
||||
X=$(./yq e < test.yml)
|
||||
assertEquals "a: frog" "$X"
|
||||
}
|
||||
|
||||
testPipeViaFileishNoParamEvalAll() {
|
||||
X=$(./yq ea < test.yml)
|
||||
assertEquals "a: frog" "$X"
|
||||
}
|
||||
|
||||
source ./scripts/shunit2
|
||||
@@ -1,83 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// import (
|
||||
// "strings"
|
||||
// "testing"
|
||||
|
||||
// "github.com/mikefarah/yq/v3/test"
|
||||
// "github.com/spf13/cobra"
|
||||
// )
|
||||
|
||||
// func getRootCommand() *cobra.Command {
|
||||
// return New()
|
||||
// }
|
||||
|
||||
// func TestRootCmd(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// if !strings.Contains(result.Output, "Usage:") {
|
||||
// t.Error("Expected usage message to be printed out, but the usage message was not found.")
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestRootCmd_Help(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "--help")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// if !strings.Contains(result.Output, "yq is a lightweight and portable command-line YAML processor. It aims to be the jq or sed of yaml files.") {
|
||||
// t.Error("Expected usage message to be printed out, but the usage message was not found.")
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestRootCmd_VerboseLong(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "--verbose")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// if !verbose {
|
||||
// t.Error("Expected verbose to be true")
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestRootCmd_VerboseShort(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "-v")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
|
||||
// if !verbose {
|
||||
// t.Error("Expected verbose to be true")
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestRootCmd_VersionShort(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "-V")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// if !strings.Contains(result.Output, "yq version") {
|
||||
// t.Error("expected version message to be printed out, but the message was not found.")
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestRootCmd_VersionLong(t *testing.T) {
|
||||
// cmd := getRootCommand()
|
||||
// result := test.RunCmd(cmd, "--version")
|
||||
// if result.Error != nil {
|
||||
// t.Error(result.Error)
|
||||
// }
|
||||
// if !strings.Contains(result.Output, "yq version") {
|
||||
// t.Error("expected version message to be printed out, but the message was not found.")
|
||||
// }
|
||||
// }
|
||||
@@ -28,3 +28,5 @@ var frontMatter = ""
|
||||
var splitFileExp = ""
|
||||
|
||||
var completedSuccessfully = false
|
||||
|
||||
var forceExpression = ""
|
||||
|
||||
+29
-11
@@ -54,6 +54,22 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
|
||||
|
||||
stat, _ := os.Stdin.Stat()
|
||||
pipingStdIn := (stat.Mode() & os.ModeCharDevice) == 0
|
||||
yqlib.GetLogger().Debug("pipingStdIn: %v", pipingStdIn)
|
||||
|
||||
yqlib.GetLogger().Debug("stat.Mode(): %v", stat.Mode())
|
||||
yqlib.GetLogger().Debug("ModeDir: %v", stat.Mode()&os.ModeDir)
|
||||
yqlib.GetLogger().Debug("ModeAppend: %v", stat.Mode()&os.ModeAppend)
|
||||
yqlib.GetLogger().Debug("ModeExclusive: %v", stat.Mode()&os.ModeExclusive)
|
||||
yqlib.GetLogger().Debug("ModeTemporary: %v", stat.Mode()&os.ModeTemporary)
|
||||
yqlib.GetLogger().Debug("ModeSymlink: %v", stat.Mode()&os.ModeSymlink)
|
||||
yqlib.GetLogger().Debug("ModeDevice: %v", stat.Mode()&os.ModeDevice)
|
||||
yqlib.GetLogger().Debug("ModeNamedPipe: %v", stat.Mode()&os.ModeNamedPipe)
|
||||
yqlib.GetLogger().Debug("ModeSocket: %v", stat.Mode()&os.ModeSocket)
|
||||
yqlib.GetLogger().Debug("ModeSetuid: %v", stat.Mode()&os.ModeSetuid)
|
||||
yqlib.GetLogger().Debug("ModeSetgid: %v", stat.Mode()&os.ModeSetgid)
|
||||
yqlib.GetLogger().Debug("ModeCharDevice: %v", stat.Mode()&os.ModeCharDevice)
|
||||
yqlib.GetLogger().Debug("ModeSticky: %v", stat.Mode()&os.ModeSticky)
|
||||
yqlib.GetLogger().Debug("ModeIrregular: %v", stat.Mode()&os.ModeIrregular)
|
||||
|
||||
out := cmd.OutOrStdout()
|
||||
|
||||
@@ -84,9 +100,13 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
|
||||
return err
|
||||
}
|
||||
|
||||
printerWriter := configurePrinterWriter(format, out)
|
||||
printerWriter, err := configurePrinterWriter(format, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encoder := configureEncoder(format)
|
||||
|
||||
printer := yqlib.NewPrinter(printerWriter, format, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
|
||||
printer := yqlib.NewPrinter(encoder, printerWriter)
|
||||
|
||||
if frontMatter != "" {
|
||||
frontMatterHandler := yqlib.NewFrontMatterHandler(args[firstFileIndex])
|
||||
@@ -105,22 +125,20 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
|
||||
}
|
||||
|
||||
allAtOnceEvaluator := yqlib.NewAllAtOnceEvaluator()
|
||||
|
||||
expression, args := processArgs(pipingStdIn, args)
|
||||
yqlib.GetLogger().Debugf("processed args: %v", args)
|
||||
|
||||
switch len(args) {
|
||||
case 0:
|
||||
if pipingStdIn {
|
||||
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer, leadingContentPreProcessing, decoder)
|
||||
if nullInput {
|
||||
err = yqlib.NewStreamEvaluator().EvaluateNew(processExpression(expression), printer, "")
|
||||
} else {
|
||||
cmd.Println(cmd.UsageString())
|
||||
return nil
|
||||
}
|
||||
case 1:
|
||||
if nullInput {
|
||||
err = yqlib.NewStreamEvaluator().EvaluateNew(processExpression(args[0]), printer, "")
|
||||
} else {
|
||||
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer, leadingContentPreProcessing, decoder)
|
||||
}
|
||||
default:
|
||||
err = allAtOnceEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer, leadingContentPreProcessing, decoder)
|
||||
err = allAtOnceEvaluator.EvaluateFiles(processExpression(expression), args, printer, leadingContentPreProcessing, decoder)
|
||||
}
|
||||
|
||||
completedSuccessfully = err == nil
|
||||
|
||||
@@ -13,7 +13,7 @@ func createEvaluateSequenceCommand() *cobra.Command {
|
||||
var cmdEvalSequence = &cobra.Command{
|
||||
Use: "eval [expression] [yaml_file1]...",
|
||||
Aliases: []string{"e"},
|
||||
Short: "Apply the expression to each document in each yaml file in sequence",
|
||||
Short: "(default) Apply the expression to each document in each yaml file in sequence",
|
||||
Example: `
|
||||
# Reads field under the given path for each file
|
||||
yq e '.a.b' f1.yml f2.yml
|
||||
@@ -44,11 +44,11 @@ expression and prints the result in sequence.`,
|
||||
}
|
||||
|
||||
func processExpression(expression string) string {
|
||||
var prettyPrintExp = `(... | (select(tag != "!!str"), select(tag == "!!str") | select(test("(?i)^(y|yes|n|no|on|off)$") | not)) ) style=""`
|
||||
|
||||
if prettyPrint && expression == "" {
|
||||
return prettyPrintExp
|
||||
return yqlib.PrettyPrintExp
|
||||
} else if prettyPrint {
|
||||
return fmt.Sprintf("%v | %v", expression, prettyPrintExp)
|
||||
return fmt.Sprintf("%v | %v", expression, yqlib.PrettyPrintExp)
|
||||
}
|
||||
return expression
|
||||
}
|
||||
@@ -67,6 +67,27 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
|
||||
|
||||
stat, _ := os.Stdin.Stat()
|
||||
pipingStdIn := (stat.Mode() & os.ModeCharDevice) == 0
|
||||
yqlib.GetLogger().Debug("pipingStdIn: %v", pipingStdIn)
|
||||
|
||||
yqlib.GetLogger().Debug("stat.Mode(): %v", stat.Mode())
|
||||
yqlib.GetLogger().Debug("ModeDir: %v", stat.Mode()&os.ModeDir)
|
||||
yqlib.GetLogger().Debug("ModeAppend: %v", stat.Mode()&os.ModeAppend)
|
||||
yqlib.GetLogger().Debug("ModeExclusive: %v", stat.Mode()&os.ModeExclusive)
|
||||
yqlib.GetLogger().Debug("ModeTemporary: %v", stat.Mode()&os.ModeTemporary)
|
||||
yqlib.GetLogger().Debug("ModeSymlink: %v", stat.Mode()&os.ModeSymlink)
|
||||
yqlib.GetLogger().Debug("ModeDevice: %v", stat.Mode()&os.ModeDevice)
|
||||
yqlib.GetLogger().Debug("ModeNamedPipe: %v", stat.Mode()&os.ModeNamedPipe)
|
||||
yqlib.GetLogger().Debug("ModeSocket: %v", stat.Mode()&os.ModeSocket)
|
||||
yqlib.GetLogger().Debug("ModeSetuid: %v", stat.Mode()&os.ModeSetuid)
|
||||
yqlib.GetLogger().Debug("ModeSetgid: %v", stat.Mode()&os.ModeSetgid)
|
||||
yqlib.GetLogger().Debug("ModeCharDevice: %v", stat.Mode()&os.ModeCharDevice)
|
||||
yqlib.GetLogger().Debug("ModeSticky: %v", stat.Mode()&os.ModeSticky)
|
||||
yqlib.GetLogger().Debug("ModeIrregular: %v", stat.Mode()&os.ModeIrregular)
|
||||
|
||||
// Mask for the type bits. For regular files, none will be set.
|
||||
yqlib.GetLogger().Debug("ModeType: %v", stat.Mode()&os.ModeType)
|
||||
|
||||
yqlib.GetLogger().Debug("ModePerm: %v", stat.Mode()&os.ModePerm)
|
||||
|
||||
out := cmd.OutOrStdout()
|
||||
|
||||
@@ -92,18 +113,22 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
|
||||
return err
|
||||
}
|
||||
|
||||
printerWriter := configurePrinterWriter(format, out)
|
||||
printerWriter, err := configurePrinterWriter(format, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encoder := configureEncoder(format)
|
||||
|
||||
printer := yqlib.NewPrinter(printerWriter, format, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
|
||||
printer := yqlib.NewPrinter(encoder, printerWriter)
|
||||
|
||||
decoder, err := configureDecoder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
streamEvaluator := yqlib.NewStreamEvaluator()
|
||||
|
||||
if frontMatter != "" {
|
||||
yqlib.GetLogger().Debug("using front matter handler")
|
||||
frontMatterHandler := yqlib.NewFrontMatterHandler(args[firstFileIndex])
|
||||
err = frontMatterHandler.Split()
|
||||
if err != nil {
|
||||
@@ -118,23 +143,18 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
|
||||
}
|
||||
defer frontMatterHandler.CleanUp()
|
||||
}
|
||||
expression, args := processArgs(pipingStdIn, args)
|
||||
|
||||
switch len(args) {
|
||||
case 0:
|
||||
if pipingStdIn {
|
||||
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer, leadingContentPreProcessing, decoder)
|
||||
if nullInput {
|
||||
err = streamEvaluator.EvaluateNew(processExpression(expression), printer, "")
|
||||
} else {
|
||||
cmd.Println(cmd.UsageString())
|
||||
return nil
|
||||
}
|
||||
case 1:
|
||||
if nullInput {
|
||||
err = streamEvaluator.EvaluateNew(processExpression(args[0]), printer, "")
|
||||
} else {
|
||||
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer, leadingContentPreProcessing, decoder)
|
||||
}
|
||||
default:
|
||||
err = streamEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer, leadingContentPreProcessing, decoder)
|
||||
err = streamEvaluator.EvaluateFiles(processExpression(expression), args, printer, leadingContentPreProcessing, decoder)
|
||||
}
|
||||
completedSuccessfully = err == nil
|
||||
|
||||
|
||||
+17
-5
@@ -14,17 +14,27 @@ func New() *cobra.Command {
|
||||
Short: "yq is a lightweight and portable command-line YAML processor.",
|
||||
Long: `yq is a portable command-line YAML processor (https://github.com/mikefarah/yq/)
|
||||
See https://mikefarah.gitbook.io/yq/ for detailed documentation and examples.`,
|
||||
Example: `
|
||||
# yq defaults to 'eval' command if no command is specified. See "yq eval --help" for more examples.
|
||||
|
||||
# read the "stuff" node from "myfile.yml"
|
||||
cat myfile.yml | yq '.stuff'
|
||||
|
||||
# update myfile.yml in place
|
||||
yq -i '.stuff = "foo"' myfile.yml # update myfile.yml inplace
|
||||
`,
|
||||
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if version {
|
||||
cmd.Print(GetVersionDisplay())
|
||||
return nil
|
||||
}
|
||||
cmd.Println(cmd.UsageString())
|
||||
return nil
|
||||
return evaluateSequence(cmd, args)
|
||||
|
||||
},
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
cmd.SetOut(cmd.OutOrStdout())
|
||||
|
||||
var format = logging.MustStringFormatter(
|
||||
`%{color}%{time:15:04:05} %{shortfunc} [%{level:.4s}]%{color:reset} %{message}`,
|
||||
)
|
||||
@@ -38,8 +48,9 @@ See https://mikefarah.gitbook.io/yq/ for detailed documentation and examples.`,
|
||||
}
|
||||
|
||||
logging.SetBackend(backend)
|
||||
yqlib.XmlPreferences.AttributePrefix = xmlAttributePrefix
|
||||
yqlib.XmlPreferences.ContentName = xmlContentName
|
||||
yqlib.InitExpressionParser()
|
||||
yqlib.XMLPreferences.AttributePrefix = xmlAttributePrefix
|
||||
yqlib.XMLPreferences.ContentName = xmlContentName
|
||||
},
|
||||
}
|
||||
|
||||
@@ -52,7 +63,7 @@ See https://mikefarah.gitbook.io/yq/ for detailed documentation and examples.`,
|
||||
}
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(&outputFormat, "output-format", "o", "yaml", "[yaml|y|json|j|props|p|xml|x] output format type.")
|
||||
rootCmd.PersistentFlags().StringVarP(&inputFormat, "input-format", "p", "yaml", "[yaml|y|xml|x] input format type. Note that json is a subset of yaml.")
|
||||
rootCmd.PersistentFlags().StringVarP(&inputFormat, "input-format", "p", "yaml", "[yaml|y|props|p|xml|x] parse format for input. Note that json is a subset of yaml.")
|
||||
|
||||
rootCmd.PersistentFlags().StringVar(&xmlAttributePrefix, "xml-attribute-prefix", "+", "prefix for xml attributes")
|
||||
rootCmd.PersistentFlags().StringVar(&xmlContentName, "xml-content-name", "+content", "name for xml content (if no attribute name is present).")
|
||||
@@ -70,6 +81,7 @@ See https://mikefarah.gitbook.io/yq/ for detailed documentation and examples.`,
|
||||
rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors")
|
||||
rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", false, "force print with no colors")
|
||||
rootCmd.PersistentFlags().StringVarP(&frontMatter, "front-matter", "f", "", "(extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact")
|
||||
rootCmd.PersistentFlags().StringVarP(&forceExpression, "expression", "", "", "forcibly set the expression argument. Useful when yq argument detection thinks your expression is a file.")
|
||||
rootCmd.PersistentFlags().BoolVarP(&leadingContentPreProcessing, "header-preprocess", "", true, "Slurp any header comments and separators before processing expression.")
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(&splitFileExp, "split-exp", "s", "", "print each result (or doc) into a file named (exp). [exp] argument must return a string. You can use $index in the expression as the result counter.")
|
||||
|
||||
+77
-6
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/mikefarah/yq/v4/pkg/yqlib"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/op/go-logging.v1"
|
||||
)
|
||||
|
||||
func initCommand(cmd *cobra.Command, args []string) (firstFileIndex int, err error) {
|
||||
@@ -51,25 +52,95 @@ func configureDecoder() (yqlib.Decoder, error) {
|
||||
return nil, err
|
||||
}
|
||||
switch yqlibInputFormat {
|
||||
case yqlib.XmlInputFormat:
|
||||
return yqlib.NewXmlDecoder(xmlAttributePrefix, xmlContentName), nil
|
||||
case yqlib.XMLInputFormat:
|
||||
return yqlib.NewXMLDecoder(xmlAttributePrefix, xmlContentName), nil
|
||||
case yqlib.PropertiesInputFormat:
|
||||
return yqlib.NewPropertiesDecoder(), nil
|
||||
}
|
||||
|
||||
return yqlib.NewYamlDecoder(), nil
|
||||
}
|
||||
|
||||
func configurePrinterWriter(format yqlib.PrinterOutputFormat, out io.Writer) yqlib.PrinterWriter {
|
||||
func configurePrinterWriter(format yqlib.PrinterOutputFormat, out io.Writer) (yqlib.PrinterWriter, error) {
|
||||
|
||||
var printerWriter yqlib.PrinterWriter
|
||||
|
||||
if splitFileExp != "" {
|
||||
colorsEnabled = forceColor
|
||||
splitExp, err := yqlib.NewExpressionParser().ParseExpression(splitFileExp)
|
||||
splitExp, err := yqlib.ExpressionParser.ParseExpression(splitFileExp)
|
||||
if err != nil {
|
||||
return nil
|
||||
return nil, fmt.Errorf("bad split document expression: %w", err)
|
||||
}
|
||||
printerWriter = yqlib.NewMultiPrinterWriter(splitExp, format)
|
||||
} else {
|
||||
printerWriter = yqlib.NewSinglePrinterWriter(out)
|
||||
}
|
||||
return printerWriter
|
||||
return printerWriter, nil
|
||||
}
|
||||
|
||||
func configureEncoder(format yqlib.PrinterOutputFormat) yqlib.Encoder {
|
||||
switch format {
|
||||
case yqlib.JSONOutputFormat:
|
||||
return yqlib.NewJONEncoder(indent)
|
||||
case yqlib.PropsOutputFormat:
|
||||
return yqlib.NewPropertiesEncoder()
|
||||
case yqlib.CSVOutputFormat:
|
||||
return yqlib.NewCsvEncoder(',')
|
||||
case yqlib.TSVOutputFormat:
|
||||
return yqlib.NewCsvEncoder('\t')
|
||||
case yqlib.YamlOutputFormat:
|
||||
return yqlib.NewYamlEncoder(indent, colorsEnabled, !noDocSeparators, unwrapScalar)
|
||||
case yqlib.XMLOutputFormat:
|
||||
return yqlib.NewXMLEncoder(indent, xmlAttributePrefix, xmlContentName)
|
||||
}
|
||||
panic("invalid encoder")
|
||||
}
|
||||
|
||||
// this is a hack to enable backwards compatibility with githubactions (which pipe /dev/null into everything)
|
||||
// and being able to call yq with the filename as a single parameter
|
||||
//
|
||||
// without this - yq detects there is stdin (thanks githubactions),
|
||||
// then tries to parse the filename as an expression
|
||||
func maybeFile(str string) bool {
|
||||
yqlib.GetLogger().Debugf("checking '%v' is a file", str)
|
||||
stat, err := os.Stat(str) // #nosec
|
||||
result := err == nil && !stat.IsDir()
|
||||
if yqlib.GetLogger().IsEnabledFor(logging.DEBUG) {
|
||||
if err != nil {
|
||||
yqlib.GetLogger().Debugf("error: %v", err)
|
||||
} else {
|
||||
yqlib.GetLogger().Debugf("error: %v, dir: %v", err, stat.IsDir())
|
||||
}
|
||||
yqlib.GetLogger().Debugf("result: %v", result)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func processStdInArgs(pipingStdin bool, args []string) []string {
|
||||
if !pipingStdin {
|
||||
return args
|
||||
}
|
||||
|
||||
for _, arg := range args {
|
||||
if arg == "-" {
|
||||
return args
|
||||
}
|
||||
}
|
||||
yqlib.GetLogger().Debugf("missing '-', adding it to the end")
|
||||
|
||||
// we're piping from stdin, but there's no '-' arg
|
||||
// lets add one to the end
|
||||
return append(args, "-")
|
||||
}
|
||||
|
||||
func processArgs(pipingStdin bool, originalArgs []string) (string, []string) {
|
||||
args := processStdInArgs(pipingStdin, originalArgs)
|
||||
yqlib.GetLogger().Debugf("processed args: %v", args)
|
||||
expression := forceExpression
|
||||
if expression == "" && len(args) > 0 && args[0] != "-" && !maybeFile(args[0]) {
|
||||
yqlib.GetLogger().Debug("assuming expression is '%v'", args[0])
|
||||
expression = args[0]
|
||||
args = args[1:]
|
||||
}
|
||||
return expression, args
|
||||
}
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ var (
|
||||
GitDescribe string
|
||||
|
||||
// Version is main version number that is being run at the moment.
|
||||
Version = "4.16.2"
|
||||
Version = "4.20.1"
|
||||
|
||||
// VersionPrerelease is a pre-release marker for the version. If this is "" (empty string)
|
||||
// then it means that it is a final release. Otherwise, this is a pre-release
|
||||
|
||||
+1
-15
@@ -1,15 +1 @@
|
||||
strings:
|
||||
- a: banana
|
||||
- a: cat
|
||||
- a: apple
|
||||
|
||||
numbers:
|
||||
- a: 12
|
||||
- a: 13
|
||||
- a: 120
|
||||
|
||||
|
||||
obj:
|
||||
- a: {cat: "adog"}
|
||||
- a: {cat: "doga"}
|
||||
- a: apple
|
||||
cat: purrs
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# comments on values appear
|
||||
person.name = Mike
|
||||
|
||||
# comments on array values appear
|
||||
person.pets.0 = cat
|
||||
person.food.0 = pizza
|
||||
+14
-2
@@ -1,2 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<cat legs="4">BiBi</cat>
|
||||
<!-- before cat -->
|
||||
<cat>
|
||||
<!-- in cat before -->
|
||||
<x>3<!-- multi
|
||||
line comment
|
||||
for x --></x>
|
||||
<y>
|
||||
<!-- in y before -->
|
||||
<d><!-- in d before -->4<!-- in d after --></d>
|
||||
<!-- in y after -->
|
||||
</y>
|
||||
<!-- in_cat_after -->
|
||||
</cat>
|
||||
<!-- after cat -->
|
||||
@@ -0,0 +1 @@
|
||||
this.is = a properties file
|
||||
@@ -0,0 +1 @@
|
||||
<this>is some xml</this>
|
||||
@@ -1,11 +1,13 @@
|
||||
module github.com/mikefarah/yq/v4
|
||||
|
||||
require (
|
||||
github.com/a8m/envsubst v1.3.0
|
||||
github.com/elliotchance/orderedmap v1.4.0
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/goccy/go-yaml v1.9.5
|
||||
github.com/jinzhu/copier v0.3.4
|
||||
github.com/jinzhu/copier v0.3.5
|
||||
github.com/magiconair/properties v1.8.5
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
|
||||
github.com/spf13/cobra v1.3.0
|
||||
github.com/timtadh/lexmachine v0.2.2
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
|
||||
|
||||
@@ -50,6 +50,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/a8m/envsubst v1.3.0 h1:GmXKmVssap0YtlU3E230W98RWtWCyIZzjtf1apWWyAg=
|
||||
github.com/a8m/envsubst v1.3.0/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
@@ -235,8 +237,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jinzhu/copier v0.3.4 h1:mfU6jI9PtCeUjkjQ322dlff9ELjGDu975C2p/nrubVI=
|
||||
github.com/jinzhu/copier v0.3.4/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
|
||||
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
@@ -292,6 +294,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/bash
|
||||
# ./yq ea '.[]' examples/data*.yaml
|
||||
|
||||
|
||||
./yq ea '
|
||||
((.[] | {.name: .}) as $item ireduce ({}; . * $item )) as $uniqueMap
|
||||
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
|
||||
' examples/data*.yaml
|
||||
@@ -19,11 +19,10 @@ type Evaluator interface {
|
||||
|
||||
type allAtOnceEvaluator struct {
|
||||
treeNavigator DataTreeNavigator
|
||||
treeCreator ExpressionParser
|
||||
}
|
||||
|
||||
func NewAllAtOnceEvaluator() Evaluator {
|
||||
return &allAtOnceEvaluator{treeNavigator: NewDataTreeNavigator(), treeCreator: NewExpressionParser()}
|
||||
return &allAtOnceEvaluator{treeNavigator: NewDataTreeNavigator()}
|
||||
}
|
||||
|
||||
func (e *allAtOnceEvaluator) EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error) {
|
||||
@@ -35,7 +34,7 @@ func (e *allAtOnceEvaluator) EvaluateNodes(expression string, nodes ...*yaml.Nod
|
||||
}
|
||||
|
||||
func (e *allAtOnceEvaluator) EvaluateCandidateNodes(expression string, inputCandidates *list.List) (*list.List, error) {
|
||||
node, err := e.treeCreator.ParseExpression(expression)
|
||||
node, err := ExpressionParser.ParseExpression(expression)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ var evaluateNodesScenario = []expressionScenario{
|
||||
}
|
||||
|
||||
func TestAllAtOnceEvaluateNodes(t *testing.T) {
|
||||
InitExpressionParser()
|
||||
var evaluator = NewAllAtOnceEvaluator()
|
||||
for _, tt := range evaluateNodesScenario {
|
||||
node := test.ParseData(tt.document)
|
||||
|
||||
@@ -136,7 +136,12 @@ func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode, prefs assignP
|
||||
n.Node.Value = ""
|
||||
}
|
||||
n.Node.Kind = other.Node.Kind
|
||||
n.Node.Tag = other.Node.Tag
|
||||
|
||||
// don't clobber custom tags...
|
||||
if strings.HasPrefix(n.Node.Tag, "!!") || n.Node.Tag == "" {
|
||||
n.Node.Tag = other.Node.Tag
|
||||
}
|
||||
|
||||
n.Node.Alias = other.Node.Alias
|
||||
|
||||
if !prefs.DontOverWriteAnchor {
|
||||
@@ -145,7 +150,10 @@ func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode, prefs assignP
|
||||
|
||||
// merge will pickup the style of the new thing
|
||||
// when autocreating nodes
|
||||
if n.Node.Style == 0 {
|
||||
//
|
||||
// if this is an empty map or empty array, use the style of other node.
|
||||
|
||||
if n.Node.Style == 0 || (n.Node.Kind != yaml.ScalarNode && len(n.Node.Content) == 0) {
|
||||
n.Node.Style = other.Node.Style
|
||||
}
|
||||
|
||||
|
||||
+14
-1
@@ -3,6 +3,7 @@ package yqlib
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
logging "gopkg.in/op/go-logging.v1"
|
||||
@@ -12,6 +13,7 @@ type Context struct {
|
||||
MatchingNodes *list.List
|
||||
Variables map[string]*list.List
|
||||
DontAutoCreate bool
|
||||
datetimeLayout string
|
||||
}
|
||||
|
||||
func (n *Context) SingleReadonlyChildContext(candidate *CandidateNode) Context {
|
||||
@@ -28,6 +30,17 @@ func (n *Context) SingleChildContext(candidate *CandidateNode) Context {
|
||||
return n.ChildContext(list)
|
||||
}
|
||||
|
||||
func (n *Context) SetDateTimeLayout(newDateTimeLayout string) {
|
||||
n.datetimeLayout = newDateTimeLayout
|
||||
}
|
||||
|
||||
func (n *Context) GetDateTimeLayout() string {
|
||||
if n.datetimeLayout != "" {
|
||||
return n.datetimeLayout
|
||||
}
|
||||
return time.RFC3339
|
||||
}
|
||||
|
||||
func (n *Context) GetVariable(name string) *list.List {
|
||||
if n.Variables == nil {
|
||||
return nil
|
||||
@@ -43,7 +56,7 @@ func (n *Context) SetVariable(name string, value *list.List) {
|
||||
}
|
||||
|
||||
func (n *Context) ChildContext(results *list.List) Context {
|
||||
clone := Context{DontAutoCreate: n.DontAutoCreate}
|
||||
clone := Context{DontAutoCreate: n.DontAutoCreate, datetimeLayout: n.datetimeLayout}
|
||||
clone.Variables = make(map[string]*list.List)
|
||||
if len(n.Variables) > 0 {
|
||||
err := copier.Copy(&clone.Variables, n.Variables)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type InputFormat uint
|
||||
|
||||
const (
|
||||
YamlInputFormat = 1 << iota
|
||||
XMLInputFormat
|
||||
PropertiesInputFormat
|
||||
)
|
||||
|
||||
type Decoder interface {
|
||||
Init(reader io.Reader)
|
||||
Decode(node *yaml.Node) error
|
||||
}
|
||||
|
||||
func InputFormatFromString(format string) (InputFormat, error) {
|
||||
switch format {
|
||||
case "yaml", "y":
|
||||
return YamlInputFormat, nil
|
||||
case "xml", "x":
|
||||
return XMLInputFormat, nil
|
||||
case "props", "p":
|
||||
return PropertiesInputFormat, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown format '%v' please use [yaml|xml|props]", format)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/magiconair/properties"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type propertiesDecoder struct {
|
||||
reader io.Reader
|
||||
finished bool
|
||||
d DataTreeNavigator
|
||||
}
|
||||
|
||||
func NewPropertiesDecoder() Decoder {
|
||||
return &propertiesDecoder{d: NewDataTreeNavigator(), finished: false}
|
||||
}
|
||||
|
||||
func (dec *propertiesDecoder) Init(reader io.Reader) {
|
||||
dec.reader = reader
|
||||
dec.finished = false
|
||||
}
|
||||
|
||||
func parsePropKey(key string) []interface{} {
|
||||
pathStrArray := strings.Split(key, ".")
|
||||
path := make([]interface{}, len(pathStrArray))
|
||||
for i, pathStr := range pathStrArray {
|
||||
num, err := strconv.ParseInt(pathStr, 10, 32)
|
||||
if err == nil {
|
||||
path[i] = num
|
||||
} else {
|
||||
path[i] = pathStr
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (dec *propertiesDecoder) processComment(c string) string {
|
||||
if c == "" {
|
||||
return ""
|
||||
}
|
||||
return "# " + c
|
||||
}
|
||||
|
||||
func (dec *propertiesDecoder) applyProperty(properties *properties.Properties, context Context, key string) error {
|
||||
value, _ := properties.Get(key)
|
||||
path := parsePropKey(key)
|
||||
|
||||
rhsNode := &yaml.Node{
|
||||
Value: value,
|
||||
Tag: "!!str",
|
||||
Kind: yaml.ScalarNode,
|
||||
LineComment: dec.processComment(properties.GetComment(key)),
|
||||
}
|
||||
|
||||
rhsNode.Tag = guessTagFromCustomType(rhsNode)
|
||||
|
||||
rhsCandidateNode := &CandidateNode{
|
||||
Path: path,
|
||||
Node: rhsNode,
|
||||
}
|
||||
|
||||
assignmentOp := &Operation{OperationType: assignOpType, Preferences: assignPreferences{}}
|
||||
|
||||
rhsOp := &Operation{OperationType: valueOpType, CandidateNode: rhsCandidateNode}
|
||||
|
||||
assignmentOpNode := &ExpressionNode{
|
||||
Operation: assignmentOp,
|
||||
LHS: createTraversalTree(path, traversePreferences{}, false),
|
||||
RHS: &ExpressionNode{Operation: rhsOp},
|
||||
}
|
||||
|
||||
_, err := dec.d.GetMatchingNodes(context, assignmentOpNode)
|
||||
return err
|
||||
}
|
||||
|
||||
func (dec *propertiesDecoder) Decode(rootYamlNode *yaml.Node) error {
|
||||
if dec.finished {
|
||||
return io.EOF
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
if _, err := buf.ReadFrom(dec.reader); err != nil {
|
||||
return err
|
||||
}
|
||||
if buf.Len() == 0 {
|
||||
dec.finished = true
|
||||
return io.EOF
|
||||
}
|
||||
properties, err := properties.LoadString(buf.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rootMap := &CandidateNode{
|
||||
Node: &yaml.Node{
|
||||
Kind: yaml.MappingNode,
|
||||
Tag: "!!map",
|
||||
},
|
||||
}
|
||||
|
||||
context := Context{}
|
||||
context = context.SingleChildContext(rootMap)
|
||||
|
||||
for _, key := range properties.Keys() {
|
||||
if err := dec.applyProperty(properties, context, key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rootYamlNode.Kind = yaml.DocumentNode
|
||||
rootYamlNode.Content = []*yaml.Node{rootMap.Node}
|
||||
dec.finished = true
|
||||
return nil
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type formatScenario struct {
|
||||
input string
|
||||
indent int
|
||||
expression string
|
||||
expected string
|
||||
description string
|
||||
subdescription string
|
||||
skipDoc bool
|
||||
scenarioType string
|
||||
}
|
||||
|
||||
func processFormatScenario(s formatScenario, decoder Decoder, encoder Encoder) string {
|
||||
|
||||
var output bytes.Buffer
|
||||
writer := bufio.NewWriter(&output)
|
||||
|
||||
if decoder == nil {
|
||||
decoder = NewYamlDecoder()
|
||||
}
|
||||
|
||||
inputs, err := readDocuments(strings.NewReader(s.input), "sample.yml", 0, decoder)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
expression := s.expression
|
||||
if expression == "" {
|
||||
expression = "."
|
||||
}
|
||||
|
||||
exp, err := getExpressionParser().ParseExpression(expression)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
context, err := NewDataTreeNavigator().GetMatchingNodes(Context{MatchingNodes: inputs}, exp)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
printer := NewPrinter(encoder, NewSinglePrinterWriter(writer))
|
||||
err = printer.PrintResults(context.MatchingNodes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
writer.Flush()
|
||||
|
||||
return output.String()
|
||||
|
||||
}
|
||||
+105
-37
@@ -2,44 +2,26 @@ package yqlib
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"golang.org/x/net/html/charset"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type InputFormat uint
|
||||
|
||||
const (
|
||||
YamlInputFormat = 1 << iota
|
||||
XmlInputFormat
|
||||
)
|
||||
|
||||
func InputFormatFromString(format string) (InputFormat, error) {
|
||||
switch format {
|
||||
case "yaml", "y":
|
||||
return YamlInputFormat, nil
|
||||
case "xml", "x":
|
||||
return XmlInputFormat, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown format '%v' please use [yaml|xml]", format)
|
||||
}
|
||||
}
|
||||
|
||||
type xmlDecoder struct {
|
||||
reader io.Reader
|
||||
attributePrefix string
|
||||
contentPrefix string
|
||||
contentName string
|
||||
finished bool
|
||||
}
|
||||
|
||||
func NewXmlDecoder(attributePrefix string, contentPrefix string) Decoder {
|
||||
if contentPrefix == "" {
|
||||
contentPrefix = "content"
|
||||
func NewXMLDecoder(attributePrefix string, contentName string) Decoder {
|
||||
if contentName == "" {
|
||||
contentName = "content"
|
||||
}
|
||||
return &xmlDecoder{attributePrefix: attributePrefix, contentPrefix: contentPrefix, finished: false}
|
||||
return &xmlDecoder{attributePrefix: attributePrefix, contentName: contentName, finished: false}
|
||||
}
|
||||
|
||||
func (dec *xmlDecoder) Init(reader io.Reader) {
|
||||
@@ -60,20 +42,41 @@ func (dec *xmlDecoder) createSequence(nodes []*xmlNode) (*yaml.Node, error) {
|
||||
return yamlNode, nil
|
||||
}
|
||||
|
||||
func (dec *xmlDecoder) processComment(c string) string {
|
||||
if c == "" {
|
||||
return ""
|
||||
}
|
||||
return "#" + strings.TrimRight(c, " ")
|
||||
}
|
||||
|
||||
func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) {
|
||||
yamlNode := &yaml.Node{Kind: yaml.MappingNode, HeadComment: n.Comment}
|
||||
log.Debug("createMap: headC: %v, footC: %v", n.HeadComment, n.FootComment)
|
||||
yamlNode := &yaml.Node{Kind: yaml.MappingNode}
|
||||
|
||||
if len(n.Data) > 0 {
|
||||
label := dec.contentPrefix
|
||||
yamlNode.Content = append(yamlNode.Content, createScalarNode(label, label), createScalarNode(n.Data, n.Data))
|
||||
label := dec.contentName
|
||||
labelNode := createScalarNode(label, label)
|
||||
labelNode.HeadComment = dec.processComment(n.HeadComment)
|
||||
labelNode.FootComment = dec.processComment(n.FootComment)
|
||||
yamlNode.Content = append(yamlNode.Content, labelNode, createScalarNode(n.Data, n.Data))
|
||||
}
|
||||
|
||||
for _, keyValuePair := range n.Children {
|
||||
for i, keyValuePair := range n.Children {
|
||||
label := keyValuePair.K
|
||||
children := keyValuePair.V
|
||||
labelNode := createScalarNode(label, label)
|
||||
var valueNode *yaml.Node
|
||||
var err error
|
||||
|
||||
if i == 0 {
|
||||
labelNode.HeadComment = dec.processComment(n.HeadComment)
|
||||
|
||||
}
|
||||
|
||||
// if i == len(n.Children)-1 {
|
||||
labelNode.FootComment = dec.processComment(keyValuePair.FootComment)
|
||||
// }
|
||||
|
||||
log.Debug("len of children in %v is %v", label, len(children))
|
||||
if len(children) > 1 {
|
||||
valueNode, err = dec.createSequence(children)
|
||||
@@ -81,6 +84,13 @@ func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// comment hack for maps of scalars
|
||||
// if the value is a scalar, the head comment of the scalar needs to go on the key?
|
||||
// add tests for <z/> as well as multiple <ds> of inputXmlWithComments > yaml
|
||||
if len(children[0].Children) == 0 && children[0].HeadComment != "" {
|
||||
labelNode.HeadComment = labelNode.HeadComment + "\n" + strings.TrimSpace(children[0].HeadComment)
|
||||
children[0].HeadComment = ""
|
||||
}
|
||||
valueNode, err = dec.convertToYamlNode(children[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -97,7 +107,14 @@ func (dec *xmlDecoder) convertToYamlNode(n *xmlNode) (*yaml.Node, error) {
|
||||
return dec.createMap(n)
|
||||
}
|
||||
scalar := createScalarNode(n.Data, n.Data)
|
||||
scalar.HeadComment = n.Comment
|
||||
if n.Data == "" {
|
||||
scalar = createScalarNode(nil, "")
|
||||
}
|
||||
log.Debug("scalar headC: %v, footC: %v", n.HeadComment, n.FootComment)
|
||||
scalar.HeadComment = dec.processComment(n.HeadComment)
|
||||
scalar.LineComment = dec.processComment(n.LineComment)
|
||||
scalar.FootComment = dec.processComment(n.FootComment)
|
||||
|
||||
return scalar, nil
|
||||
}
|
||||
|
||||
@@ -107,7 +124,7 @@ func (dec *xmlDecoder) Decode(rootYamlNode *yaml.Node) error {
|
||||
}
|
||||
root := &xmlNode{}
|
||||
// cant use xj - it doesn't keep map order.
|
||||
err := dec.decodeXml(root)
|
||||
err := dec.decodeXML(root)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -116,6 +133,9 @@ func (dec *xmlDecoder) Decode(rootYamlNode *yaml.Node) error {
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if firstNode.Tag == "!!null" {
|
||||
dec.finished = true
|
||||
return io.EOF
|
||||
}
|
||||
rootYamlNode.Kind = yaml.DocumentNode
|
||||
rootYamlNode.Content = []*yaml.Node{firstNode}
|
||||
@@ -124,14 +144,17 @@ func (dec *xmlDecoder) Decode(rootYamlNode *yaml.Node) error {
|
||||
}
|
||||
|
||||
type xmlNode struct {
|
||||
Children []*xmlChildrenKv
|
||||
Comment string
|
||||
Data string
|
||||
Children []*xmlChildrenKv
|
||||
HeadComment string
|
||||
FootComment string
|
||||
LineComment string
|
||||
Data string
|
||||
}
|
||||
|
||||
type xmlChildrenKv struct {
|
||||
K string
|
||||
V []*xmlNode
|
||||
K string
|
||||
V []*xmlNode
|
||||
FootComment string
|
||||
}
|
||||
|
||||
// AddChild appends a node to the list of children
|
||||
@@ -158,12 +181,13 @@ type element struct {
|
||||
parent *element
|
||||
n *xmlNode
|
||||
label string
|
||||
state string
|
||||
}
|
||||
|
||||
// this code is heavily based on https://github.com/basgys/goxml2json
|
||||
// main changes are to decode into a structure that preserves the original order
|
||||
// of the map keys.
|
||||
func (dec *xmlDecoder) decodeXml(root *xmlNode) error {
|
||||
func (dec *xmlDecoder) decodeXML(root *xmlNode) error {
|
||||
xmlDec := xml.NewDecoder(dec.reader)
|
||||
|
||||
// That will convert the charset if the provided XML is non-UTF-8
|
||||
@@ -183,6 +207,8 @@ func (dec *xmlDecoder) decodeXml(root *xmlNode) error {
|
||||
|
||||
switch se := t.(type) {
|
||||
case xml.StartElement:
|
||||
log.Debug("start element %v", se.Name.Local)
|
||||
elem.state = "started"
|
||||
// Build new a new current element and link it to its parent
|
||||
elem = &element{
|
||||
parent: elem,
|
||||
@@ -197,7 +223,13 @@ func (dec *xmlDecoder) decodeXml(root *xmlNode) error {
|
||||
case xml.CharData:
|
||||
// Extract XML data (if any)
|
||||
elem.n.Data = trimNonGraphic(string(se))
|
||||
if elem.n.Data != "" {
|
||||
elem.state = "chardata"
|
||||
log.Debug("chardata [%v] for %v", elem.n.Data, elem.label)
|
||||
}
|
||||
case xml.EndElement:
|
||||
log.Debug("end element %v", elem.label)
|
||||
elem.state = "finished"
|
||||
// And add it to its parent list
|
||||
if elem.parent != nil {
|
||||
elem.parent.n.AddChild(elem.label, elem.n)
|
||||
@@ -206,13 +238,49 @@ func (dec *xmlDecoder) decodeXml(root *xmlNode) error {
|
||||
// Then change the current element to its parent
|
||||
elem = elem.parent
|
||||
case xml.Comment:
|
||||
elem.n.Comment = trimNonGraphic(string(xml.CharData(se)))
|
||||
|
||||
commentStr := string(xml.CharData(se))
|
||||
if elem.state == "started" {
|
||||
applyFootComment(elem, commentStr)
|
||||
|
||||
} else if elem.state == "chardata" {
|
||||
log.Debug("got a line comment for (%v) %v: [%v]", elem.state, elem.label, commentStr)
|
||||
elem.n.LineComment = joinFilter([]string{elem.n.LineComment, commentStr})
|
||||
} else {
|
||||
log.Debug("got a head comment for (%v) %v: [%v]", elem.state, elem.label, commentStr)
|
||||
elem.n.HeadComment = joinFilter([]string{elem.n.HeadComment, commentStr})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyFootComment(elem *element, commentStr string) {
|
||||
|
||||
// first lets try to put the comment on the last child
|
||||
if len(elem.n.Children) > 0 {
|
||||
lastChildIndex := len(elem.n.Children) - 1
|
||||
childKv := elem.n.Children[lastChildIndex]
|
||||
log.Debug("got a foot comment for %v: [%v]", childKv.K, commentStr)
|
||||
childKv.FootComment = joinFilter([]string{elem.n.FootComment, commentStr})
|
||||
} else {
|
||||
log.Debug("got a foot comment for %v: [%v]", elem.label, commentStr)
|
||||
elem.n.FootComment = joinFilter([]string{elem.n.FootComment, commentStr})
|
||||
}
|
||||
}
|
||||
|
||||
func joinFilter(rawStrings []string) string {
|
||||
stringsToJoin := make([]string, 0)
|
||||
for _, str := range rawStrings {
|
||||
if str != "" {
|
||||
stringsToJoin = append(stringsToJoin, str)
|
||||
}
|
||||
}
|
||||
return strings.Join(stringsToJoin, " ")
|
||||
}
|
||||
|
||||
// trimNonGraphic returns a slice of the string s, with all leading and trailing
|
||||
// non graphic characters and spaces removed.
|
||||
//
|
||||
|
||||
@@ -6,11 +6,6 @@ import (
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Decoder interface {
|
||||
Init(reader io.Reader)
|
||||
Decode(node *yaml.Node) error
|
||||
}
|
||||
|
||||
type yamlDecoder struct {
|
||||
decoder yaml.Decoder
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
+158
-102
@@ -4,31 +4,16 @@ Add behaves differently according to the type of the LHS:
|
||||
* arrays: concatenate
|
||||
* number scalars: arithmetic addition
|
||||
* string scalars: concatenate
|
||||
* maps: shallow merge (use the multiply operator (`*`) to deeply merge)
|
||||
|
||||
Use `+=` as append assign for things like increment. Note that `.a += .x` is equivalent to running `.a = .a + .x`.
|
||||
Use `+=` as a relative append assign for things like increment. Note that `.a += .x` is equivalent to running `.a = .a + .x`.
|
||||
|
||||
## Concatenate and assign arrays
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
val: thing
|
||||
b:
|
||||
- cat
|
||||
- dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.b += ["cow"]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a:
|
||||
val: thing
|
||||
b:
|
||||
- cat
|
||||
- dog
|
||||
- cow
|
||||
```
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Concatenate arrays
|
||||
Given a sample.yml file of:
|
||||
@@ -42,7 +27,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a + .b' sample.yml
|
||||
yq '.a + .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -52,6 +37,28 @@ will output
|
||||
- 4
|
||||
```
|
||||
|
||||
## Concatenate to existing array
|
||||
Note that the styling of `a` is kept.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: [1,2]
|
||||
b:
|
||||
- 3
|
||||
- 4
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a += .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: [1, 2, 3, 4]
|
||||
b:
|
||||
- 3
|
||||
- 4
|
||||
```
|
||||
|
||||
## Concatenate null to array
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -61,7 +68,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a + null' sample.yml
|
||||
yq '.a + null' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -69,6 +76,22 @@ will output
|
||||
- 2
|
||||
```
|
||||
|
||||
## Append to existing array
|
||||
Note that the styling is copied from existing array elements
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: ['dog']
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a += "cat"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: ['dog', 'cat']
|
||||
```
|
||||
|
||||
## Add new object to array
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -77,7 +100,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a + {"cat": "meow"}' sample.yml
|
||||
yq '.a + {"cat": "meow"}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -85,76 +108,6 @@ will output
|
||||
- cat: meow
|
||||
```
|
||||
|
||||
## Add string to array
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
- 1
|
||||
- 2
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a + "hello"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
- 1
|
||||
- 2
|
||||
- hello
|
||||
```
|
||||
|
||||
## Append to array
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
- 1
|
||||
- 2
|
||||
b:
|
||||
- 3
|
||||
- 4
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = .a + .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- 4
|
||||
b:
|
||||
- 3
|
||||
- 4
|
||||
```
|
||||
|
||||
## Append another array using +=
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
- 1
|
||||
- 2
|
||||
b:
|
||||
- 3
|
||||
- 4
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a += .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- 4
|
||||
b:
|
||||
- 3
|
||||
- 4
|
||||
```
|
||||
|
||||
## Relative append
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -169,7 +122,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a[].b += ["mouse"]' sample.yml
|
||||
yq '.a[].b += ["mouse"]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -193,7 +146,7 @@ b: meow
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = .a + .b' sample.yml
|
||||
yq '.a += .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -211,7 +164,7 @@ b: 4.9
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = .a + .b' sample.yml
|
||||
yq '.a = .a + .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -229,7 +182,7 @@ b: 4
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = .a + .b' sample.yml
|
||||
yq '.a = .a + .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -245,7 +198,7 @@ b: 5
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] += 1' sample.yml
|
||||
yq '.[] += 1' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -253,15 +206,118 @@ a: 4
|
||||
b: 6
|
||||
```
|
||||
|
||||
## Date addition
|
||||
You can add durations to dates. Assumes RFC3339 date time format, see [date-time operators](https://mikefarah.gitbook.io/yq/operators/date-time-operators) for more information.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: 2021-01-01T00:00:00Z
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a += "3h10m"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: 2021-01-01T03:10:00Z
|
||||
```
|
||||
|
||||
## Date addition - custom format
|
||||
You can add durations to dates. See [date-time operators](https://mikefarah.gitbook.io/yq/operators/date-time-operators) for more information.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 2:59AM GMT
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'with_dtf("Monday, 02-Jan-06 at 3:04PM MST", .a += "3h1m")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 6:00AM GMT
|
||||
```
|
||||
|
||||
## Add to null
|
||||
Adding to null simply returns the rhs
|
||||
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input 'null + "cat"'
|
||||
yq --null-input 'null + "cat"'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cat
|
||||
```
|
||||
|
||||
## Add maps to shallow merge
|
||||
Adding objects together shallow merges them. Use `*` to deeply merge.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
thing:
|
||||
name: Astuff
|
||||
value: x
|
||||
a1: cool
|
||||
b:
|
||||
thing:
|
||||
name: Bstuff
|
||||
legs: 3
|
||||
b1: neat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a += .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a:
|
||||
thing:
|
||||
name: Bstuff
|
||||
legs: 3
|
||||
a1: cool
|
||||
b1: neat
|
||||
b:
|
||||
thing:
|
||||
name: Bstuff
|
||||
legs: 3
|
||||
b1: neat
|
||||
```
|
||||
|
||||
## Custom types: that are really strings
|
||||
When custom tags are encountered, yq will try to decode the underlying type.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: !horse cat
|
||||
b: !goat _meow
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a += .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: !horse cat_meow
|
||||
b: !goat _meow
|
||||
```
|
||||
|
||||
## Custom types: that are really numbers
|
||||
When custom tags are encountered, yq will try to decode the underlying type.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: !horse 1.2
|
||||
b: !goat 2.3
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a += .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: !horse 3.5
|
||||
b: !goat 2.3
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
This operator is used to provide alternative (or default) values when a particular expression is either null or false.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## LHS is defined
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -9,7 +15,7 @@ a: bridge
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a // "hello"' sample.yml
|
||||
yq '.a // "hello"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -23,7 +29,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a // "hello"' sample.yml
|
||||
yq '.a // "hello"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -37,7 +43,7 @@ a: ~
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a // "hello"' sample.yml
|
||||
yq '.a // "hello"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -51,7 +57,7 @@ a: false
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a // "hello"' sample.yml
|
||||
yq '.a // "hello"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -66,7 +72,7 @@ b: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a // .b' sample.yml
|
||||
yq '.a // .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -5,6 +5,12 @@ Use the `alias` and `anchor` operators to read and write yaml aliases and anchor
|
||||
`yq` supports merge aliases (like `<<: *blah`) however this is no longer in the standard yaml spec (1.2) and so `yq` will automatically add the `!!merge` tag to these nodes as it is effectively a custom tag.
|
||||
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Merge one map
|
||||
see https://yaml.org/type/merge.html
|
||||
|
||||
@@ -25,7 +31,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[4] | explode(.)' sample.yml
|
||||
yq '.[4] | explode(.)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -55,7 +61,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[4] | explode(.)' sample.yml
|
||||
yq '.[4] | explode(.)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -87,7 +93,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[4] | explode(.)' sample.yml
|
||||
yq '.[4] | explode(.)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -103,7 +109,7 @@ a: &billyBob cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | anchor' sample.yml
|
||||
yq '.a | anchor' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -117,7 +123,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a anchor = "foobar"' sample.yml
|
||||
yq '.a anchor = "foobar"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -132,7 +138,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a anchor |= .b' sample.yml
|
||||
yq '.a anchor |= .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -148,7 +154,7 @@ a: *billyBob
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | alias' sample.yml
|
||||
yq '.a | alias' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -163,7 +169,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a alias = "meow"' sample.yml
|
||||
yq '.a alias = "meow"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -179,7 +185,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a alias = ""' sample.yml
|
||||
yq '.a alias = ""' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -196,7 +202,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a alias |= .f' sample.yml
|
||||
yq '.a alias |= .f' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -213,7 +219,7 @@ f:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'explode(.f)' sample.yml
|
||||
yq 'explode(.f)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -229,7 +235,7 @@ a: mike
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'explode(.a)' sample.yml
|
||||
yq 'explode(.a)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -245,7 +251,7 @@ f:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'explode(.f)' sample.yml
|
||||
yq 'explode(.f)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -278,7 +284,7 @@ foobar:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'explode(.)' sample.yml
|
||||
yq 'explode(.)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -317,7 +323,7 @@ thingTwo:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.thingOne |= explode(.) * {"value": false}' sample.yml
|
||||
yq '.thingOne |= explode(.) * {"value": false}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -7,10 +7,16 @@ Which will assign the LHS node values to the RHS node values. The RHS expression
|
||||
|
||||
### relative form: `|=`
|
||||
This will do a similar thing to the plain form, however, the RHS expression is run against _the LHS nodes_. This is useful for updating values based on old values, e.g. increment.
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Create yaml file
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '.a.b = "cat" | .x = "frog"'
|
||||
yq --null-input '.a.b = "cat" | .x = "frog"'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -28,7 +34,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a |= .b' sample.yml
|
||||
yq '.a |= .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -45,7 +51,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] |= . * 2' sample.yml
|
||||
yq '.[] |= . * 2' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -84,7 +90,7 @@ b: sibling
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = .b' sample.yml
|
||||
yq '.a = .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -101,7 +107,7 @@ c: fieldC
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '(.a, .c) = "potatoe"' sample.yml
|
||||
yq '(.a, .c) = "potatoe"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -118,7 +124,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.b = "frog"' sample.yml
|
||||
yq '.a.b = "frog"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -136,7 +142,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.b |= "frog"' sample.yml
|
||||
yq '.a.b |= "frog"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -155,7 +161,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '(.a[] | select(. == "apple")) = "frog"' sample.yml
|
||||
yq '(.a[] | select(. == "apple")) = "frog"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -173,7 +179,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '(.[] | select(. == "*andy")) = "bogs"' sample.yml
|
||||
yq '(.[] | select(. == "*andy")) = "bogs"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -189,7 +195,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.b |= "bogs"' sample.yml
|
||||
yq '.a.b |= "bogs"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -205,7 +211,7 @@ a: &cool cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = "dog"' sample.yml
|
||||
yq '.a = "dog"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -219,7 +225,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.b.[0] |= "bogs"' sample.yml
|
||||
yq '.a.b.[0] |= "bogs"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -10,10 +10,16 @@ The `or` and `and` operators take two parameters and return a boolean result.
|
||||
|
||||
These are most commonly used with the `select` operator to filter particular nodes.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## `or` example
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input 'true or false'
|
||||
yq --null-input 'true or false'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -23,7 +29,7 @@ true
|
||||
## `and` example
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input 'true and false'
|
||||
yq --null-input 'true and false'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -42,7 +48,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '[.[] | select(.a == "cat" or .b == "dog")]' sample.yml
|
||||
yq '[.[] | select(.a == "cat" or .b == "dog")]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -60,7 +66,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'any' sample.yml
|
||||
yq 'any' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -74,7 +80,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'any' sample.yml
|
||||
yq 'any' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -93,7 +99,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] |= any_c(. == "awesome")' sample.yml
|
||||
yq '.[] |= any_c(. == "awesome")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -109,7 +115,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'all' sample.yml
|
||||
yq 'all' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -123,7 +129,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'all' sample.yml
|
||||
yq 'all' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -142,7 +148,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] |= all_c(tag == "!!str")' sample.yml
|
||||
yq '.[] |= all_c(tag == "!!str")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -153,7 +159,7 @@ b: false
|
||||
## Not true is false
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input 'true | not'
|
||||
yq --null-input 'true | not'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -163,7 +169,7 @@ false
|
||||
## Not false is true
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input 'false | not'
|
||||
yq --null-input 'false | not'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -173,7 +179,7 @@ true
|
||||
## String values considered to be true
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '"cat" | not'
|
||||
yq --null-input '"cat" | not'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -183,7 +189,7 @@ false
|
||||
## Empty string value considered to be true
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '"" | not'
|
||||
yq --null-input '"" | not'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -193,7 +199,7 @@ false
|
||||
## Numbers are considered to be true
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '1 | not'
|
||||
yq --null-input '1 | not'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -203,7 +209,7 @@ false
|
||||
## Zero is considered to be true
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '0 | not'
|
||||
yq --null-input '0 | not'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -213,7 +219,7 @@ false
|
||||
## Null is considered to be false
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '~ | not'
|
||||
yq --null-input '~ | not'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -3,10 +3,16 @@
|
||||
This creates an array using the expression between the square brackets.
|
||||
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Collect empty
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '[]'
|
||||
yq --null-input '[]'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -16,7 +22,7 @@ will output
|
||||
## Collect single
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '["cat"]'
|
||||
yq --null-input '["cat"]'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -31,7 +37,7 @@ b: dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '[.a, .b]' sample.yml
|
||||
yq '[.a, .b]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -10,6 +10,12 @@ This will assign the LHS nodes comments to the expression on the RHS. The RHS is
|
||||
### relative form: `|=`
|
||||
Similar to the plain form, however the RHS evaluates against each matching LHS node! This is useful if you want to set the comments as a relative expression of the node, for instance its value or path.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Set line comment
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -17,7 +23,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a lineComment="single"' sample.yml
|
||||
yq '.a line_comment="single"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -32,7 +38,7 @@ b: dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.. lineComment |= .' sample.yml
|
||||
yq '.. line_comment |= .' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -47,7 +53,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '. headComment="single"' sample.yml
|
||||
yq '. head_comment="single"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -63,7 +69,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '. footComment=.a' sample.yml
|
||||
yq '. foot_comment=.a' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -80,7 +86,7 @@ b: dog # leave this
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a lineComment=""' sample.yml
|
||||
yq '.a line_comment=""' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -99,7 +105,7 @@ b: # key comment
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '... comments=""' sample.yml
|
||||
yq '... comments=""' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -114,7 +120,7 @@ a: cat # meow
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | lineComment' sample.yml
|
||||
yq '.a | line_comment' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -132,7 +138,7 @@ a: cat # meow
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '. | headComment' sample.yml
|
||||
yq '. | head_comment' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -151,7 +157,7 @@ a: cat # meow
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'headComment' sample.yml
|
||||
yq 'head_comment' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -171,7 +177,7 @@ a: cat # meow
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '. | footComment' sample.yml
|
||||
yq '. | foot_comment' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
This returns `true` if the context contains the passed in parameter, and false otherwise.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Array contains array
|
||||
Array is equal or subset of
|
||||
|
||||
@@ -13,7 +19,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'contains(["baz", "bar"])' sample.yml
|
||||
yq 'contains(["baz", "bar"])' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -32,7 +38,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'contains({"bar": [{"barp": 12}]})' sample.yml
|
||||
yq 'contains({"bar": [{"barp": 12}]})' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -51,7 +57,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'contains({"foo": 12, "bar": [{"barp": 15}]})' sample.yml
|
||||
yq 'contains({"foo": 12, "bar": [{"barp": 15}]})' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -65,7 +71,7 @@ foobar
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'contains("bar")' sample.yml
|
||||
yq 'contains("bar")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -79,7 +85,7 @@ meow
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'contains("meow")' sample.yml
|
||||
yq 'contains("meow")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
|
||||
This is used to construct objects (or maps). This can be used against existing yaml, or to create fresh yaml documents.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Collect empty object
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '{}'
|
||||
yq --null-input '{}'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -19,7 +25,7 @@ name: Mike
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '{"wrap": .}' sample.yml
|
||||
yq '{"wrap": .}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -37,7 +43,7 @@ pets:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '{.name: .pets.[]}' sample.yml
|
||||
yq '{.name: .pets.[]}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -60,7 +66,7 @@ pets:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '{.name: .pets.[]}' sample.yml
|
||||
yq '{.name: .pets.[]}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -73,7 +79,7 @@ Rosey: sheep
|
||||
## Creating yaml from scratch
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '{"wrap": "frog"}'
|
||||
yq --null-input '{"wrap": "frog"}'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
# Date Time
|
||||
|
||||
Various operators for parsing and manipulating dates.
|
||||
|
||||
## Date time formattings
|
||||
This uses the golangs built in time library for parsing and formatting date times.
|
||||
|
||||
When not specified, the RFC3339 standard is assumed `2006-01-02T15:04:05Z07:00` for parsing.
|
||||
|
||||
To specify a custom parsing format, use the `with_dtf` operator. The first parameter sets the datetime parsing format for the expression in the second parameter. The expression can be any valid `yq` expression tree.
|
||||
|
||||
```bash
|
||||
yq 'with_dtf("myformat"; .a + "3h" | tz("Australia/Melbourne"))'
|
||||
```
|
||||
|
||||
See https://pkg.go.dev/time#pkg-constants for examples of formatting options.
|
||||
|
||||
|
||||
## Timezones
|
||||
This uses golangs built in LoadLocation function to parse timezones strings. See https://pkg.go.dev/time#LoadLocation for more details.
|
||||
|
||||
|
||||
## Durations
|
||||
Durations are parsed using golangs built in [ParseDuration](https://pkg.go.dev/time#ParseDuration) function.
|
||||
|
||||
You can durations to time using the `+` operator.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Format: from standard RFC3339 format
|
||||
Providing a single parameter assumes a standard RFC3339 datetime format. If the target format is not a valid yaml datetime format, the result will be a string tagged node.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: 2001-12-15T02:59:43.1Z
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a |= format_datetime("Monday, 02-Jan-06 at 3:04PM")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 2:59AM
|
||||
```
|
||||
|
||||
## Format: from custom date time
|
||||
Use with_dtf to set a custom datetime format for parsing.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 2:59AM
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a |= with_dtf("Monday, 02-Jan-06 at 3:04PM"; format_datetime("2006-01-02"))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: 2001-12-15
|
||||
```
|
||||
|
||||
## Format: get the day of the week
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: 2001-12-15T02:59:43.1Z
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a | format_datetime("Monday")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
Saturday
|
||||
```
|
||||
|
||||
## Now
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cool
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.updated = now' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: cool
|
||||
updated: 2021-05-19T01:02:03Z
|
||||
```
|
||||
|
||||
## Timezone: from standard RFC3339 format
|
||||
Returns a new datetime in the specified timezone. Specify standard IANA Time Zone format or 'utc', 'local'. When given a single parameter, this assumes the datetime is in RFC3339 format.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cool
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.updated = (now | tz("Australia/Sydney"))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: cool
|
||||
updated: 2021-05-19T11:02:03+10:00
|
||||
```
|
||||
|
||||
## Timezone: with custom format
|
||||
Specify standard IANA Time Zone format or 'utc', 'local'
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 2:59AM GMT
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a |= with_dtf("Monday, 02-Jan-06 at 3:04PM MST"; tz("Australia/Sydney"))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 1:59PM AEDT
|
||||
```
|
||||
|
||||
## Add and tz custom format
|
||||
Specify standard IANA Time Zone format or 'utc', 'local'
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 2:59AM GMT
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a |= with_dtf("Monday, 02-Jan-06 at 3:04PM MST"; tz("Australia/Sydney"))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 1:59PM AEDT
|
||||
```
|
||||
|
||||
## Date addition
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: 2021-01-01T00:00:00Z
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a += "3h10m"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: 2021-01-01T03:10:00Z
|
||||
```
|
||||
|
||||
## Date subtraction
|
||||
You can subtract durations from dates. Assumes RFC3339 date time format, see [date-time operators](https://mikefarah.gitbook.io/yq/operators/date-time-operators) for more information.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: 2021-01-01T03:10:00Z
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a -= "3h10m"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: 2021-01-01T00:00:00Z
|
||||
```
|
||||
|
||||
## Date addition - custom format
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 2:59AM GMT
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'with_dtf("Monday, 02-Jan-06 at 3:04PM MST"; .a += "3h1m")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 6:00AM GMT
|
||||
```
|
||||
|
||||
## Date script with custom format
|
||||
You can embed full expressions in with_dtf if needed.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 2:59AM GMT
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'with_dtf("Monday, 02-Jan-06 at 3:04PM MST"; .a = (.a + "3h1m" | tz("Australia/Perth")))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 2:00PM AWST
|
||||
```
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Deletes matching entries in maps or arrays.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Delete entry in map
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -10,7 +16,7 @@ b: dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'del(.b)' sample.yml
|
||||
yq 'del(.b)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -26,7 +32,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'del(.a.a1)' sample.yml
|
||||
yq 'del(.a.a1)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -43,7 +49,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'del(.[1])' sample.yml
|
||||
yq 'del(.[1])' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -59,7 +65,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'del(.[0].a)' sample.yml
|
||||
yq 'del(.[0].a)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -74,7 +80,7 @@ b: dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'del(.c)' sample.yml
|
||||
yq 'del(.c)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -91,7 +97,7 @@ c: bat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'del( .[] | select(. == "*at") )' sample.yml
|
||||
yq 'del( .[] | select(. == "*at") )' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -109,7 +115,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'del(.. | select(has("name")).name)' sample.yml
|
||||
yq 'del(.. | select(has("name")).name)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Use the `documentIndex` operator (or the `di` shorthand) to select nodes of a particular document.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Retrieve a document index
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -11,7 +17,7 @@ a: frog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | documentIndex' sample.yml
|
||||
yq '.a | document_index' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -29,7 +35,7 @@ a: frog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | di' sample.yml
|
||||
yq '.a | di' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -47,7 +53,7 @@ a: frog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'select(documentIndex == 1)' sample.yml
|
||||
yq 'select(document_index == 1)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -63,7 +69,7 @@ a: frog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'select(di == 1)' sample.yml
|
||||
yq 'select(di == 1)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -79,7 +85,7 @@ a: frog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | ({"match": ., "doc": documentIndex})' sample.yml
|
||||
yq '.a | ({"match": ., "doc": document_index})' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -22,6 +22,12 @@ CSV and TSV format both accept either a single array or scalars (representing a
|
||||
XML uses the `--xml-attribute-prefix` and `xml-content-name` flags to identify attributes and content fields.
|
||||
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Encode value as json string
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -30,7 +36,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.b = (.a | to_json)' sample.yml
|
||||
yq '.b = (.a | to_json)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -52,7 +58,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.b = (.a | to_json(0))' sample.yml
|
||||
yq '.b = (.a | to_json(0))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -71,7 +77,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.b = (.a | @json)' sample.yml
|
||||
yq '.b = (.a | @json)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -89,7 +95,7 @@ a: '{"cool":"thing"}'
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | from_json | ... style=""' sample.yml
|
||||
yq '.a | from_json | ... style=""' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -104,7 +110,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.b = (.a | @props)' sample.yml
|
||||
yq '.b = (.a | @props)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -125,7 +131,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.b = (.a | to_yaml)' sample.yml
|
||||
yq '.b = (.a | to_yaml)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -148,7 +154,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.b = (.a | to_yaml(8))' sample.yml
|
||||
yq '.b = (.a | to_yaml(8))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -167,7 +173,7 @@ a: 'foo: bar'
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.b = (.a | from_yaml)' sample.yml
|
||||
yq '.b = (.a | from_yaml)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -186,7 +192,7 @@ a: |
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a |= (from_yaml | .foo = "cat" | to_yaml)' sample.yml
|
||||
yq '.a |= (from_yaml | .foo = "cat" | to_yaml)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -202,7 +208,7 @@ a: 'foo: bar'
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a |= (from_yaml | .foo = "cat" | to_yaml)' sample.yml
|
||||
yq '.a |= (from_yaml | .foo = "cat" | to_yaml)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -221,7 +227,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '@csv' sample.yml
|
||||
yq '@csv' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -242,7 +248,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '@csv' sample.yml
|
||||
yq '@csv' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -266,7 +272,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '@tsv' sample.yml
|
||||
yq '@tsv' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -284,7 +290,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | to_xml' sample.yml
|
||||
yq '.a | to_xml' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -304,7 +310,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | @xml' sample.yml
|
||||
yq '.a | @xml' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -322,7 +328,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '{"cat": .a | to_xml(1)}' sample.yml
|
||||
yq '{"cat": .a | to_xml(1)}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -339,7 +345,7 @@ a: <foo>bar</foo>
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.b = (.a | from_xml)' sample.yml
|
||||
yq '.b = (.a | from_xml)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Similar to the same named functions in `jq` these functions convert to/from an object and an array of key-value pairs. This is most useful for performing operations on keys of maps.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## to_entries Map
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -10,7 +16,7 @@ b: 2
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'to_entries' sample.yml
|
||||
yq 'to_entries' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -28,7 +34,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'to_entries' sample.yml
|
||||
yq 'to_entries' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -45,7 +51,7 @@ null
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'to_entries' sample.yml
|
||||
yq 'to_entries' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -59,7 +65,7 @@ b: 2
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'to_entries | from_entries' sample.yml
|
||||
yq 'to_entries | from_entries' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -77,7 +83,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'to_entries | from_entries' sample.yml
|
||||
yq 'to_entries | from_entries' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -93,7 +99,7 @@ b: 2
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'with_entries(.key |= "KEY_" + .)' sample.yml
|
||||
yq 'with_entries(.key |= "KEY_" + .)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -111,7 +117,7 @@ c:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'with_entries(select(.value | has("b")))' sample.yml
|
||||
yq 'with_entries(select(.value | has("b")))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -1,11 +1,32 @@
|
||||
# Env Variable Operators
|
||||
|
||||
This operator is used to handle environment variables usage in path expressions. While environment variables can, of course, be passed in via your CLI with string interpolation, this often comes with complex quote escaping and can be tricky to write and read. Note that there are two forms, `env` which will parse the environment variable as a yaml (be it a map, array, string, number of boolean) and `strenv` which will always parse the argument as a string.
|
||||
These operators are used to handle environment variables usage in expressions and documents. While environment variables can, of course, be passed in via your CLI with string interpolation, this often comes with complex quote escaping and can be tricky to write and read.
|
||||
|
||||
There are three operators:
|
||||
- `env` which takes a single environment variable name and parse the variable as a yaml node (be it a map, array, string, number of boolean)
|
||||
- `strenv` which also takes a single environment variable name, and always parses the variable as a string.
|
||||
- `envsubst` which you pipe strings into and it interpolates environment variables in strings using [envsubst](https://github.com/a8m/envsubst).
|
||||
|
||||
|
||||
## Tip
|
||||
To replace environment variables across all values in a document, `envsubst` can be used with the recursive descent operator
|
||||
as follows:
|
||||
|
||||
```bash
|
||||
yq '(.. | select(tag == "!!str")) |= envsubst' file.yaml
|
||||
```
|
||||
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Read string environment variable
|
||||
Running
|
||||
```bash
|
||||
myenv="cat meow" yq eval --null-input '.a = env(myenv)'
|
||||
myenv="cat meow" yq --null-input '.a = env(myenv)'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -15,7 +36,7 @@ a: cat meow
|
||||
## Read boolean environment variable
|
||||
Running
|
||||
```bash
|
||||
myenv="true" yq eval --null-input '.a = env(myenv)'
|
||||
myenv="true" yq --null-input '.a = env(myenv)'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -25,7 +46,7 @@ a: true
|
||||
## Read numeric environment variable
|
||||
Running
|
||||
```bash
|
||||
myenv="12" yq eval --null-input '.a = env(myenv)'
|
||||
myenv="12" yq --null-input '.a = env(myenv)'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -35,7 +56,7 @@ a: 12
|
||||
## Read yaml environment variable
|
||||
Running
|
||||
```bash
|
||||
myenv="{b: fish}" yq eval --null-input '.a = env(myenv)'
|
||||
myenv="{b: fish}" yq --null-input '.a = env(myenv)'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -45,7 +66,7 @@ a: {b: fish}
|
||||
## Read boolean environment variable as a string
|
||||
Running
|
||||
```bash
|
||||
myenv="true" yq eval --null-input '.a = strenv(myenv)'
|
||||
myenv="true" yq --null-input '.a = strenv(myenv)'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -55,13 +76,35 @@ a: "true"
|
||||
## Read numeric environment variable as a string
|
||||
Running
|
||||
```bash
|
||||
myenv="12" yq eval --null-input '.a = strenv(myenv)'
|
||||
myenv="12" yq --null-input '.a = strenv(myenv)'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: "12"
|
||||
```
|
||||
|
||||
## Dynamically update a path from an environment variable
|
||||
The env variable can be any valid yq expression.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
b:
|
||||
- name: dog
|
||||
- name: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
pathEnv=".a.b[0].name" valueEnv="moo" yq 'eval(strenv(pathEnv)) = strenv(valueEnv)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a:
|
||||
b:
|
||||
- name: moo
|
||||
- name: cat
|
||||
```
|
||||
|
||||
## Dynamic key lookup with environment variable
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -70,10 +113,54 @@ dog: woof
|
||||
```
|
||||
then
|
||||
```bash
|
||||
myenv="cat" yq eval '.[env(myenv)]' sample.yml
|
||||
myenv="cat" yq '.[env(myenv)]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
meow
|
||||
```
|
||||
|
||||
## Replace strings with envsubst
|
||||
Running
|
||||
```bash
|
||||
myenv="cat" yq --null-input '"the ${myenv} meows" | envsubst'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
the cat meows
|
||||
```
|
||||
|
||||
## Replace strings with envsubst, missing variables
|
||||
Running
|
||||
```bash
|
||||
myenv="cat" yq --null-input '"the ${myenvnonexisting} meows" | envsubst'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
the meows
|
||||
```
|
||||
|
||||
## Replace strings with envsubst, missing variables with defaults
|
||||
Running
|
||||
```bash
|
||||
myenv="cat" yq --null-input '"the ${myenvnonexisting-dog} meows" | envsubst'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
the dog meows
|
||||
```
|
||||
|
||||
## Replace string environment variable in document
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
v: ${myenv}
|
||||
```
|
||||
then
|
||||
```bash
|
||||
myenv="cat meow" yq '.v |= envsubst' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
v: cat meow
|
||||
```
|
||||
|
||||
|
||||
@@ -12,6 +12,12 @@ It is most often used with the select operator to find particular nodes:
|
||||
select(.a == .b)
|
||||
```
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Match string
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -21,7 +27,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | (. == "*at")' sample.yml
|
||||
yq '.[] | (. == "*at")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -39,7 +45,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | (. != "*at")' sample.yml
|
||||
yq '.[] | (. != "*at")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -57,7 +63,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | (. == 4)' sample.yml
|
||||
yq '.[] | (. == 4)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -75,7 +81,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | (. != 4)' sample.yml
|
||||
yq '.[] | (. != 4)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -87,7 +93,7 @@ true
|
||||
## Match nulls
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input 'null == ~'
|
||||
yq --null-input 'null == ~'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -101,7 +107,7 @@ a: frog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'select(.b != "thing")' sample.yml
|
||||
yq 'select(.b != "thing")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -115,7 +121,7 @@ a: frog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'select(.b == .c)' sample.yml
|
||||
yq 'select(.b == .c)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# Eval
|
||||
|
||||
Use `eval` to dynamically process an expression - for instance from an environment variable.
|
||||
|
||||
`eval` takes a single argument, and evaluates that as a `yq` expression. Any valid expression can be used, beit a path `.a.b.c | select(. == "cat")`, or an update `.a.b.c = "gogo"`.
|
||||
|
||||
Tip: This can be useful way parameterise complex scripts.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Dynamically evaluate a path
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
pathExp: .a.b[] | select(.name == "cat")
|
||||
a:
|
||||
b:
|
||||
- name: dog
|
||||
- name: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'eval(.pathExp)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
name: cat
|
||||
```
|
||||
|
||||
## Dynamically update a path from an environment variable
|
||||
The env variable can be any valid yq expression.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
b:
|
||||
- name: dog
|
||||
- name: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
pathEnv=".a.b[0].name" valueEnv="moo" yq 'eval(strenv(pathEnv)) = strenv(valueEnv)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a:
|
||||
b:
|
||||
- name: moo
|
||||
- name: cat
|
||||
```
|
||||
|
||||
@@ -10,6 +10,12 @@ Note the use of eval-all to ensure all documents are loaded into memory.
|
||||
yq eval-all 'select(fi == 0) * select(filename == "file2.yaml")' file1.yaml file2.yaml
|
||||
```
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Get filename
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -17,7 +23,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'filename' sample.yml
|
||||
yq 'filename' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -31,7 +37,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'fileIndex' sample.yml
|
||||
yq 'file_index' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -49,7 +55,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval-all 'fileIndex' sample.yml another.yml
|
||||
yq eval-all 'file_index' sample.yml another.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -65,7 +71,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'fi' sample.yml
|
||||
yq 'fi' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
# Flatten
|
||||
This recursively flattens arrays.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Flatten
|
||||
Recursively flattens all arrays
|
||||
|
||||
@@ -12,7 +18,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'flatten' sample.yml
|
||||
yq 'flatten' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -30,7 +36,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'flatten(1)' sample.yml
|
||||
yq 'flatten(1)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -46,7 +52,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'flatten' sample.yml
|
||||
yq 'flatten' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -61,7 +67,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'flatten' sample.yml
|
||||
yq 'flatten' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
This is used to group items in an array by an expression.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Group by field
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -14,7 +20,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'group_by(.foo)' sample.yml
|
||||
yq 'group_by(.foo)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -40,7 +46,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'group_by(.foo)' sample.yml
|
||||
yq 'group_by(.foo)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
This is operation that returns true if the key exists in a map (or index in an array), false otherwise.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Has map key
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -12,7 +18,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | has("a")' sample.yml
|
||||
yq '.[] | has("a")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -36,7 +42,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | select(.a.b | has("c"))' sample.yml
|
||||
yq '.[] | select(.a.b | has("c"))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -57,7 +63,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | has(1)' sample.yml
|
||||
yq '.[] | has(1)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
yq [eval/eval-all] [expression] files..
|
||||
|
||||
eval/e - Apply the expression to each document in each yaml file in sequence
|
||||
eval/e - (default) Apply the expression to each document in each yaml file in sequence
|
||||
|
||||
eval-all/ea - Loads all yaml documents of all yaml files and runs expression once
|
||||
|
||||
@@ -18,32 +18,33 @@ This documentation is also available at https://mikefarah.gitbook.io/yq/
|
||||
|
||||
## Read a value:
|
||||
```bash
|
||||
yq e '.a.b[0].c' file.yaml
|
||||
yq '.a.b[0].c' file.yaml
|
||||
```
|
||||
|
||||
## Pipe from STDIN:
|
||||
```bash
|
||||
cat file.yaml | yq e '.a.b[0].c' -
|
||||
cat file.yaml | yq '.a.b[0].c'
|
||||
```
|
||||
|
||||
## Update a yaml file, inplace
|
||||
```bash
|
||||
yq e -i '.a.b[0].c = "cool"' file.yaml
|
||||
yq -i '.a.b[0].c = "cool"' file.yaml
|
||||
```
|
||||
|
||||
## Update using environment variables
|
||||
```bash
|
||||
NAME=mike yq e -i '.a.b[0].c = strenv(NAME)' file.yaml
|
||||
NAME=mike yq -i '.a.b[0].c = strenv(NAME)' file.yaml
|
||||
```
|
||||
|
||||
## Merge multiple files
|
||||
```
|
||||
yq ea '. as $item ireduce ({}; . * $item )' path/to/*.yml
|
||||
```
|
||||
Note the use of `ea` to evaluate all files at once (instead of in sequence.)
|
||||
|
||||
## Multiple updates to a yaml file
|
||||
```bash
|
||||
yq e -i '
|
||||
yq -i '
|
||||
.a.b[0].c = "cool" |
|
||||
.x.y.z = "foobar" |
|
||||
.person.name = strenv(NAME)
|
||||
|
||||
@@ -4,5 +4,7 @@ Add behaves differently according to the type of the LHS:
|
||||
* arrays: concatenate
|
||||
* number scalars: arithmetic addition
|
||||
* string scalars: concatenate
|
||||
* maps: shallow merge (use the multiply operator (`*`) to deeply merge)
|
||||
|
||||
Use `+=` as a relative append assign for things like increment. Note that `.a += .x` is equivalent to running `.a = .a + .x`.
|
||||
|
||||
Use `+=` as append assign for things like increment. Note that `.a += .x` is equivalent to running `.a = .a + .x`.
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Date Time
|
||||
|
||||
Various operators for parsing and manipulating dates.
|
||||
|
||||
## Date time formattings
|
||||
This uses the golangs built in time library for parsing and formatting date times.
|
||||
|
||||
When not specified, the RFC3339 standard is assumed `2006-01-02T15:04:05Z07:00` for parsing.
|
||||
|
||||
To specify a custom parsing format, use the `with_dtf` operator. The first parameter sets the datetime parsing format for the expression in the second parameter. The expression can be any valid `yq` expression tree.
|
||||
|
||||
```bash
|
||||
yq 'with_dtf("myformat"; .a + "3h" | tz("Australia/Melbourne"))'
|
||||
```
|
||||
|
||||
See https://pkg.go.dev/time#pkg-constants for examples of formatting options.
|
||||
|
||||
|
||||
## Timezones
|
||||
This uses golangs built in LoadLocation function to parse timezones strings. See https://pkg.go.dev/time#LoadLocation for more details.
|
||||
|
||||
|
||||
## Durations
|
||||
Durations are parsed using golangs built in [ParseDuration](https://pkg.go.dev/time#ParseDuration) function.
|
||||
|
||||
You can durations to time using the `+` operator.
|
||||
@@ -1,3 +1,18 @@
|
||||
# Env Variable Operators
|
||||
|
||||
This operator is used to handle environment variables usage in path expressions. While environment variables can, of course, be passed in via your CLI with string interpolation, this often comes with complex quote escaping and can be tricky to write and read. Note that there are two forms, `env` which will parse the environment variable as a yaml (be it a map, array, string, number of boolean) and `strenv` which will always parse the argument as a string.
|
||||
These operators are used to handle environment variables usage in expressions and documents. While environment variables can, of course, be passed in via your CLI with string interpolation, this often comes with complex quote escaping and can be tricky to write and read.
|
||||
|
||||
There are three operators:
|
||||
- `env` which takes a single environment variable name and parse the variable as a yaml node (be it a map, array, string, number of boolean)
|
||||
- `strenv` which also takes a single environment variable name, and always parses the variable as a string.
|
||||
- `envsubst` which you pipe strings into and it interpolates environment variables in strings using [envsubst](https://github.com/a8m/envsubst).
|
||||
|
||||
|
||||
## Tip
|
||||
To replace environment variables across all values in a document, `envsubst` can be used with the recursive descent operator
|
||||
as follows:
|
||||
|
||||
```bash
|
||||
yq '(.. | select(tag == "!!str")) |= envsubst' file.yaml
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# Eval
|
||||
|
||||
Use `eval` to dynamically process an expression - for instance from an environment variable.
|
||||
|
||||
`eval` takes a single argument, and evaluates that as a `yq` expression. Any valid expression can be used, beit a path `.a.b.c | select(. == "cat")`, or an update `.a.b.c = "gogo"`.
|
||||
|
||||
Tip: This can be useful way parameterise complex scripts.
|
||||
@@ -1,10 +1,17 @@
|
||||
# Load
|
||||
|
||||
The `load`/`strload` operator allows you to load in content from another file referenced in your yaml document.
|
||||
The load operators allows you to load in content from another file.
|
||||
|
||||
Note that you can use string operators like `+` and `sub` to modify the value in the yaml file to a path that exists in your system.
|
||||
|
||||
Use `strload` to load text based content as a string block, and `load` to interpret the file as yaml.
|
||||
You can load files of the following supported types:
|
||||
|
||||
|Format | Load Operator |
|
||||
| --- | --- |
|
||||
| Yaml | load |
|
||||
| XML | load_xml |
|
||||
| Properties | load_props |
|
||||
| Plain String | load_str |
|
||||
|
||||
Lets say there is a file `../../examples/thing.yml`:
|
||||
|
||||
@@ -12,3 +19,14 @@ Lets say there is a file `../../examples/thing.yml`:
|
||||
a: apple is included
|
||||
b: cool
|
||||
```
|
||||
and a file `small.xml`:
|
||||
|
||||
```xml
|
||||
<this>is some xml</this>
|
||||
```
|
||||
|
||||
and `small.properties`:
|
||||
|
||||
```properties
|
||||
this.is = a properties file
|
||||
```
|
||||
|
||||
@@ -10,9 +10,10 @@ Note that when merging objects, this operator returns the merged object (not the
|
||||
### Merge Flags
|
||||
You can control how objects are merged by using one or more of the following flags. Multiple flags can be used together, e.g. `.a *+? .b`. See examples below
|
||||
|
||||
- `+` to append arrays
|
||||
- `?` to only merge existing fields
|
||||
- `d` to deeply merge arrays
|
||||
- `+` append arrays
|
||||
- `d` deeply merge arrays
|
||||
- `?` only merge _existing_ fields
|
||||
- `n` only merge _new_ fields
|
||||
|
||||
### Merging files
|
||||
Note the use of `eval-all` to ensure all documents are loaded into memory.
|
||||
|
||||
@@ -8,7 +8,7 @@ This will, like the `jq` equivalent, recursively match all _value_ nodes. Use it
|
||||
For instance to set the `style` of all _value_ nodes in a yaml doc, excluding map keys:
|
||||
|
||||
```bash
|
||||
yq eval '.. style= "flow"' file.yaml
|
||||
yq '.. style= "flow"' file.yaml
|
||||
```
|
||||
|
||||
## match values and map keys form `...`
|
||||
@@ -17,5 +17,5 @@ The also includes map keys in the results set. This is particularly useful in YA
|
||||
For instance to set the `style` of all nodes in a yaml doc, including the map keys:
|
||||
|
||||
```bash
|
||||
yq eval '... style= "flow"' file.yaml
|
||||
yq '... style= "flow"' file.yaml
|
||||
```
|
||||
@@ -5,7 +5,9 @@ The Sort Keys operator sorts maps by their keys (based on their string value). T
|
||||
Sort is particularly useful for diffing two different yaml documents:
|
||||
|
||||
```bash
|
||||
yq eval -i -P 'sort_keys(..)' file1.yml
|
||||
yq eval -i -P 'sort_keys(..)' file2.yml
|
||||
yq -i -P 'sort_keys(..)' file1.yml
|
||||
yq -i -P 'sort_keys(..)' file2.yml
|
||||
diff file1.yml file2.yml
|
||||
```
|
||||
|
||||
Note that `yq` does not yet consider anchors when sorting by keys - this may result in invalid yaml documents if your are using merge anchors.
|
||||
|
||||
@@ -17,13 +17,13 @@ a: |
|
||||
Using `$( exp )` wont work, as it will trim the trailing new line.
|
||||
|
||||
```
|
||||
m=$(echo "cat\n") yq e -n '.a = strenv(m)'
|
||||
m=$(echo "cat\n") yq -n '.a = strenv(m)'
|
||||
a: cat
|
||||
```
|
||||
|
||||
However, using printf works:
|
||||
```
|
||||
printf -v m "cat\n" ; m="$m" yq e -n '.a = strenv(m)'
|
||||
printf -v m "cat\n" ; m="$m" yq -n '.a = strenv(m)'
|
||||
a: |
|
||||
cat
|
||||
```
|
||||
@@ -31,7 +31,7 @@ a: |
|
||||
As well as having multiline expressions:
|
||||
```
|
||||
m="cat
|
||||
" yq e -n '.a = strenv(m)'
|
||||
" yq -n '.a = strenv(m)'
|
||||
a: |
|
||||
cat
|
||||
```
|
||||
@@ -40,5 +40,5 @@ Similarly, if you're trying to set the content from a file, and want a trailing
|
||||
|
||||
```
|
||||
IFS= read -rd '' output < <(cat my_file)
|
||||
output=$output ./yq e '.data.values = strenv(output)' first.yml
|
||||
output=$output ./yq '.data.values = strenv(output)' first.yml
|
||||
```
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Use the `keys` operator to return map keys or array indices.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Map keys
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -10,7 +16,7 @@ cat: meow
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'keys' sample.yml
|
||||
yq 'keys' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -26,7 +32,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'keys' sample.yml
|
||||
yq 'keys' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -43,7 +49,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[1] | key' sample.yml
|
||||
yq '.[1] | key' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -57,7 +63,7 @@ a: thing
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | key' sample.yml
|
||||
yq '.a | key' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -71,7 +77,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'key' sample.yml
|
||||
yq 'key' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -86,7 +92,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '(.a.x | key) = "meow"' sample.yml
|
||||
yq '(.a.x | key) = "meow"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -105,7 +111,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.x | key | headComment' sample.yml
|
||||
yq '.a.x | key | headComment' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Returns the lengths of the nodes. Length is defined according to the type of the node.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## String length
|
||||
returns length of string
|
||||
|
||||
@@ -11,7 +17,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | length' sample.yml
|
||||
yq '.a | length' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -25,7 +31,7 @@ a: null
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | length' sample.yml
|
||||
yq '.a | length' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -42,7 +48,7 @@ c: dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'length' sample.yml
|
||||
yq 'length' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -61,7 +67,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'length' sample.yml
|
||||
yq 'length' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
# Load
|
||||
|
||||
The `load`/`strload` operator allows you to load in content from another file referenced in your yaml document.
|
||||
The load operators allows you to load in content from another file.
|
||||
|
||||
Note that you can use string operators like `+` and `sub` to modify the value in the yaml file to a path that exists in your system.
|
||||
|
||||
Use `strload` to load text based content as a string block, and `load` to interpret the file as yaml.
|
||||
You can load files of the following supported types:
|
||||
|
||||
|Format | Load Operator |
|
||||
| --- | --- |
|
||||
| Yaml | load |
|
||||
| XML | load_xml |
|
||||
| Properties | load_props |
|
||||
| Plain String | load_str |
|
||||
|
||||
Lets say there is a file `../../examples/thing.yml`:
|
||||
|
||||
@@ -12,6 +19,23 @@ Lets say there is a file `../../examples/thing.yml`:
|
||||
a: apple is included
|
||||
b: cool
|
||||
```
|
||||
and a file `small.xml`:
|
||||
|
||||
```xml
|
||||
<this>is some xml</this>
|
||||
```
|
||||
|
||||
and `small.properties`:
|
||||
|
||||
```properties
|
||||
this.is = a properties file
|
||||
```
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Simple example
|
||||
Given a sample.yml file of:
|
||||
@@ -20,7 +44,7 @@ myFile: ../../examples/thing.yml
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'load(.myFile)' sample.yml
|
||||
yq 'load(.myFile)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -38,7 +62,7 @@ something:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.something |= load("../../examples/" + .file)' sample.yml
|
||||
yq '.something |= load("../../examples/" + .file)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -60,7 +84,7 @@ over:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '(.. | select(has("file"))) |= load("../../examples/" + .file)' sample.yml
|
||||
yq '(.. | select(has("file"))) |= load("../../examples/" + .file)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -83,7 +107,7 @@ something:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.something |= strload("../../examples/" + .file)' sample.yml
|
||||
yq '.something |= load_str("../../examples/" + .file)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -92,3 +116,56 @@ something: |-
|
||||
b: cool.
|
||||
```
|
||||
|
||||
## Load from XML
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
cool: things
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.more_stuff = load_xml("../../examples/small.xml")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cool: things
|
||||
more_stuff:
|
||||
this: is some xml
|
||||
```
|
||||
|
||||
## Load from Properties
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
cool: things
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.more_stuff = load_props("../../examples/small.properties")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cool: things
|
||||
more_stuff:
|
||||
this:
|
||||
is: a properties file
|
||||
```
|
||||
|
||||
## Merge from properties
|
||||
This can be used as a convenient way to update a yaml document
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
this:
|
||||
is: from yaml
|
||||
cool: ay
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '. *= load_props("../../examples/small.properties")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
this:
|
||||
is: a properties file
|
||||
cool: ay
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Maps values of an array. Use `map_values` to map values of an object.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Map array
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -11,7 +17,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'map(. + 1)' sample.yml
|
||||
yq 'map(. + 1)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -29,7 +35,7 @@ c: 3
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'map_values(. + 1)' sample.yml
|
||||
yq 'map_values(. + 1)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -10,9 +10,10 @@ Note that when merging objects, this operator returns the merged object (not the
|
||||
### Merge Flags
|
||||
You can control how objects are merged by using one or more of the following flags. Multiple flags can be used together, e.g. `.a *+? .b`. See examples below
|
||||
|
||||
- `+` to append arrays
|
||||
- `?` to only merge existing fields
|
||||
- `d` to deeply merge arrays
|
||||
- `+` append arrays
|
||||
- `d` deeply merge arrays
|
||||
- `?` only merge _existing_ fields
|
||||
- `n` only merge _new_ fields
|
||||
|
||||
### Merging files
|
||||
Note the use of `eval-all` to ensure all documents are loaded into memory.
|
||||
@@ -21,14 +22,26 @@ Note the use of `eval-all` to ensure all documents are loaded into memory.
|
||||
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' file1.yaml file2.yaml
|
||||
```
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Multiply integers
|
||||
Running
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: 3
|
||||
b: 4
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval --null-input '3 * 4'
|
||||
yq '.a *= .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
12
|
||||
a: 12
|
||||
b: 4
|
||||
```
|
||||
|
||||
## Merge objects together, returning merged result only
|
||||
@@ -44,7 +57,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a * .b' sample.yml
|
||||
yq '.a * .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -67,7 +80,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '. * {"a":.b}' sample.yml
|
||||
yq '. * {"a":.b}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -91,7 +104,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '. * {"a":.b}' sample.yml
|
||||
yq '. * {"a":.b}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -114,7 +127,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '. * {"a":.b}' sample.yml
|
||||
yq '. * {"a":.b}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -140,7 +153,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a *? .b' sample.yml
|
||||
yq '.a *? .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -148,6 +161,27 @@ thing: two
|
||||
cat: frog
|
||||
```
|
||||
|
||||
## Merge, only new fields
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
thing: one
|
||||
cat: frog
|
||||
b:
|
||||
missing: two
|
||||
thing: two
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a *n .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
thing: one
|
||||
cat: frog
|
||||
missing: two
|
||||
```
|
||||
|
||||
## Merge, appending arrays
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -166,7 +200,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a *+ .b' sample.yml
|
||||
yq '.a *+ .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -196,7 +230,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a *?+ .b' sample.yml
|
||||
yq '.a *?+ .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -223,7 +257,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a *d .b' sample.yml
|
||||
yq '.a *d .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -234,18 +268,23 @@ will output
|
||||
```
|
||||
|
||||
## Merge arrays of objects together, matching on a key
|
||||
|
||||
This is a fairly complex expression - you can use it as is by providing the environment variables as seen in the example below.
|
||||
|
||||
It merges in the array provided in the second file into the first - matching on equal keys.
|
||||
|
||||
Explanation:
|
||||
|
||||
The approach, at a high level, is to reduce into a merged map (keyed by the unique key)
|
||||
and then convert that back into an array.
|
||||
|
||||
First the expression will create a map from the arrays keyed by '.a', the unique field we want to merge by.
|
||||
First the expression will create a map from the arrays keyed by the idPath, the unique field we want to merge by.
|
||||
The reduce operator is merging '({}; . * $item )', so array elements with the matching key will be merged together.
|
||||
|
||||
Next, we convert the map back to an array, using reduce again, concatenating all the map values together.
|
||||
|
||||
Finally, we set the result of the merged array back into the first doc.
|
||||
|
||||
To use this, you will need to update '.myArray' in the expression to your array (e.g. .my.array), and '.a' to be the key field of your array (e.g. '.name')
|
||||
|
||||
Thanks Kev from [stackoverflow](https://stackoverflow.com/a/70109529/1168223)
|
||||
|
||||
|
||||
@@ -262,7 +301,7 @@ something: else
|
||||
```
|
||||
And another sample another.yml file of:
|
||||
```yaml
|
||||
myArray:
|
||||
newArray:
|
||||
- a: banana
|
||||
c: bananaC
|
||||
- a: apple
|
||||
@@ -272,12 +311,12 @@ myArray:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval-all '
|
||||
idPath=".a" originalPath=".myArray" otherPath=".newArray" yq eval-all '
|
||||
(
|
||||
((.myArray[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap
|
||||
(( (eval(strenv(originalPath)) + eval(strenv(otherPath))) | .[] | {(eval(strenv(idPath))): .}) as $item ireduce ({}; . * $item )) as $uniqueMap
|
||||
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
|
||||
) as $mergedArray
|
||||
| select(fi == 0) | .myArray = $mergedArray
|
||||
| select(fi == 0) | (eval(strenv(originalPath))) = $mergedArray
|
||||
' sample.yml another.yml
|
||||
```
|
||||
will output
|
||||
@@ -303,7 +342,7 @@ b: dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '. * {"a": {"c": .a}}' sample.yml
|
||||
yq '. * {"a": {"c": .a}}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -324,7 +363,7 @@ c:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.c * .b' sample.yml
|
||||
yq '.c * .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -344,7 +383,7 @@ c:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.c * .a' sample.yml
|
||||
yq '.c * .a' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -376,7 +415,7 @@ foobar:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.foobar * .foobarList' sample.yml
|
||||
yq '.foobar * .foobarList' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -388,3 +427,44 @@ thing: foobar_thing
|
||||
b: foobarList_b
|
||||
```
|
||||
|
||||
## Custom types: that are really numbers
|
||||
When custom tags are encountered, yq will try to decode the underlying type.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: !horse 2
|
||||
b: !goat 3
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a = .a * .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: !horse 6
|
||||
b: !goat 3
|
||||
```
|
||||
|
||||
## Custom types: that are really maps
|
||||
Custom tags will be maintained.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: !horse
|
||||
cat: meow
|
||||
b: !goat
|
||||
dog: woof
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a = .a * .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: !horse
|
||||
cat: meow
|
||||
dog: woof
|
||||
b: !goat
|
||||
dog: woof
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Parent simply returns the parent nodes of the matching nodes.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Simple example
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -10,7 +16,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.nested | parent' sample.yml
|
||||
yq '.a.nested | parent' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -29,7 +35,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.. | select(. == "banana") | parent' sample.yml
|
||||
yq '.. | select(. == "banana") | parent' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -44,7 +50,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'parent' sample.yml
|
||||
yq 'parent' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -4,6 +4,12 @@ The path operator can be used to get the traversal paths of matching nodes in an
|
||||
|
||||
You can get the key/index of matching nodes by using the `path` operator to return the path array then piping that through `.[-1]` to get the last element of that array, the key.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Map path
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -12,7 +18,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.b | path' sample.yml
|
||||
yq '.a.b | path' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -28,7 +34,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.b | path | .[-1]' sample.yml
|
||||
yq '.a.b | path | .[-1]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -44,7 +50,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.[] | select(. == "dog") | path' sample.yml
|
||||
yq '.a.[] | select(. == "dog") | path' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -61,7 +67,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.[] | select(. == "dog") | path | .[-1]' sample.yml
|
||||
yq '.a.[] | select(. == "dog") | path | .[-1]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -78,7 +84,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml
|
||||
yq '.a[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Pipe the results of an expression into another. Like the bash operator.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Simple Pipe
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -10,7 +16,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | .b' sample.yml
|
||||
yq '.a | .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -26,7 +32,7 @@ c: same
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = "cat" | .b = "dog"' sample.yml
|
||||
yq '.a = "cat" | .b = "dog"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -8,7 +8,7 @@ This will, like the `jq` equivalent, recursively match all _value_ nodes. Use it
|
||||
For instance to set the `style` of all _value_ nodes in a yaml doc, excluding map keys:
|
||||
|
||||
```bash
|
||||
yq eval '.. style= "flow"' file.yaml
|
||||
yq '.. style= "flow"' file.yaml
|
||||
```
|
||||
|
||||
## match values and map keys form `...`
|
||||
@@ -17,8 +17,14 @@ The also includes map keys in the results set. This is particularly useful in YA
|
||||
For instance to set the `style` of all nodes in a yaml doc, including the map keys:
|
||||
|
||||
```bash
|
||||
yq eval '... style= "flow"' file.yaml
|
||||
yq '... style= "flow"' file.yaml
|
||||
```
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Recurse map (values only)
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -26,7 +32,7 @@ a: frog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '..' sample.yml
|
||||
yq '..' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -47,7 +53,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '[.. | select(has("name"))]' sample.yml
|
||||
yq '[.. | select(has("name"))]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -70,7 +76,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.. | select(. == "frog")' sample.yml
|
||||
yq '.. | select(. == "frog")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -87,7 +93,7 @@ a: frog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '...' sample.yml
|
||||
yq '...' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -105,7 +111,7 @@ b: *cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '[..]' sample.yml
|
||||
yq '[..]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -142,7 +148,7 @@ foobar:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.foobar | [..]' sample.yml
|
||||
yq '.foobar | [..]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -21,6 +21,12 @@ Reduce syntax in `yq` is a little different from `jq` - as `yq` (currently) isn'
|
||||
|
||||
To that end, the reduce operator is called `ireduce` for backwards compatability if a `jq` like prefix version of `reduce` is ever added.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Sum numbers
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -31,7 +37,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] as $item ireduce (0; . + $item)' sample.yml
|
||||
yq '.[] as $item ireduce (0; . + $item)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -67,7 +73,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] as $item ireduce ({}; .[$item | .name] = ($item | .has) )' sample.yml
|
||||
yq '.[] as $item ireduce ({}; .[$item | .name] = ($item | .has) )' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
|
||||
Select is used to filter arrays and maps by a boolean expression.
|
||||
|
||||
## Select elements from array
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Select elements from array using wildcard prefix
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- cat
|
||||
@@ -11,7 +17,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | select(. == "*at")' sample.yml
|
||||
yq '.[] | select(. == "*at")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -19,7 +25,99 @@ cat
|
||||
goat
|
||||
```
|
||||
|
||||
## Select and update matching values in map
|
||||
## Select elements from array using wildcard suffix
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- go-kart
|
||||
- goat
|
||||
- dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.[] | select(. == "go*")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
go-kart
|
||||
goat
|
||||
```
|
||||
|
||||
## Select elements from array using wildcard prefix and suffix
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- ago
|
||||
- go
|
||||
- meow
|
||||
- going
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.[] | select(. == "*go*")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
ago
|
||||
go
|
||||
going
|
||||
```
|
||||
|
||||
## Select elements from array with regular expression
|
||||
See more regular expression examples under the `string` operator docs.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- this_0
|
||||
- not_this
|
||||
- nor_0_this
|
||||
- thisTo_4
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.[] | select(test("[a-zA-Z]+_[0-9]$"))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
this_0
|
||||
thisTo_4
|
||||
```
|
||||
|
||||
## Select items from a map
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
things: cat
|
||||
bob: goat
|
||||
horse: dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.[] | select(. == "cat" or test("og$"))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cat
|
||||
dog
|
||||
```
|
||||
|
||||
## Use select and with_entries to filter map keys
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
name: bob
|
||||
legs: 2
|
||||
game: poker
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'with_entries(select(.key | test("ame$")))' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
name: bob
|
||||
game: poker
|
||||
```
|
||||
|
||||
## Select multiple items in a map and update
|
||||
Note the brackets around the entire LHS.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
@@ -29,7 +127,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '(.a.[] | select(. == "*at")) |= "rabbit"' sample.yml
|
||||
yq '(.a.[] | select(. == "cat" or . == "goat")) |= "rabbit"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -5,11 +5,19 @@ The Sort Keys operator sorts maps by their keys (based on their string value). T
|
||||
Sort is particularly useful for diffing two different yaml documents:
|
||||
|
||||
```bash
|
||||
yq eval -i -P 'sort_keys(..)' file1.yml
|
||||
yq eval -i -P 'sort_keys(..)' file2.yml
|
||||
yq -i -P 'sort_keys(..)' file1.yml
|
||||
yq -i -P 'sort_keys(..)' file2.yml
|
||||
diff file1.yml file2.yml
|
||||
```
|
||||
|
||||
Note that `yq` does not yet consider anchors when sorting by keys - this may result in invalid yaml documents if your are using merge anchors.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Sort keys of map
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -19,7 +27,7 @@ b: bing
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'sort_keys(.)' sample.yml
|
||||
yq 'sort_keys(.)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -49,7 +57,7 @@ aParent:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'sort_keys(..)' sample.yml
|
||||
yq 'sort_keys(..)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -4,6 +4,12 @@ Sorts an array. Use `sort` to sort an array as is, or `sort_by(exp)` to sort by
|
||||
|
||||
Note that at this stage, `yq` only sorts scalar fields.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Sort by string field
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -13,7 +19,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'sort_by(.a)' sample.yml
|
||||
yq 'sort_by(.a)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -32,7 +38,7 @@ cool:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.cool |= sort_by(.a)' sample.yml
|
||||
yq '.cool |= sort_by(.a)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -54,7 +60,7 @@ cool:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.cool |= sort_by(keys | .[0])' sample.yml
|
||||
yq '.cool |= sort_by(keys | .[0])' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -80,7 +86,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'sort_by(.a)' sample.yml
|
||||
yq 'sort_by(.a)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -103,7 +109,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'sort_by(.a)' sample.yml
|
||||
yq 'sort_by(.a)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -125,7 +131,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'sort' sample.yml
|
||||
yq 'sort' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
|
||||
This operator splits all matches into separate documents
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Split empty
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input 'splitDoc'
|
||||
yq --null-input 'split_doc'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -20,7 +26,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | splitDoc' sample.yml
|
||||
yq '.[] | split_doc' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -17,13 +17,13 @@ a: |
|
||||
Using `$( exp )` wont work, as it will trim the trailing new line.
|
||||
|
||||
```
|
||||
m=$(echo "cat\n") yq e -n '.a = strenv(m)'
|
||||
m=$(echo "cat\n") yq -n '.a = strenv(m)'
|
||||
a: cat
|
||||
```
|
||||
|
||||
However, using printf works:
|
||||
```
|
||||
printf -v m "cat\n" ; m="$m" yq e -n '.a = strenv(m)'
|
||||
printf -v m "cat\n" ; m="$m" yq -n '.a = strenv(m)'
|
||||
a: |
|
||||
cat
|
||||
```
|
||||
@@ -31,7 +31,7 @@ a: |
|
||||
As well as having multiline expressions:
|
||||
```
|
||||
m="cat
|
||||
" yq e -n '.a = strenv(m)'
|
||||
" yq -n '.a = strenv(m)'
|
||||
a: |
|
||||
cat
|
||||
```
|
||||
@@ -40,9 +40,15 @@ Similarly, if you're trying to set the content from a file, and want a trailing
|
||||
|
||||
```
|
||||
IFS= read -rd '' output < <(cat my_file)
|
||||
output=$output ./yq e '.data.values = strenv(output)' first.yml
|
||||
output=$output ./yq '.data.values = strenv(output)' first.yml
|
||||
```
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Join strings
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -54,7 +60,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'join("; ")' sample.yml
|
||||
yq 'join("; ")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -68,7 +74,7 @@ foo bar foo
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'match("foo")' sample.yml
|
||||
yq 'match("foo")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -85,7 +91,7 @@ foo bar FOO
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '[match("(?i)foo"; "g")]' sample.yml
|
||||
yq '[match("(?i)foo"; "g")]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -106,7 +112,7 @@ abc abc
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '[match("(abc)+"; "g")]' sample.yml
|
||||
yq '[match("(abc)+"; "g")]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -133,7 +139,7 @@ foo bar foo foo foo
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '[match("foo (?P<bar123>bar)? foo"; "g")]' sample.yml
|
||||
yq '[match("foo (?P<bar123>bar)? foo"; "g")]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -162,7 +168,7 @@ xyzzy-14
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)")' sample.yml
|
||||
yq 'capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -177,7 +183,7 @@ cat cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'match("cat")' sample.yml
|
||||
yq 'match("cat")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -194,7 +200,7 @@ cat cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '[match("cat"; "g")]' sample.yml
|
||||
yq '[match("cat"; "g")]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -218,7 +224,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | test("at")' sample.yml
|
||||
yq '.[] | test("at")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -236,7 +242,7 @@ a: dogs are great
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a |= sub("dogs", "cats")' sample.yml
|
||||
yq '.a |= sub("dogs", "cats")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -254,7 +260,7 @@ b: heat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] |= sub("(a)", "${1}r")' sample.yml
|
||||
yq '.[] |= sub("(a)", "${1}r")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -269,7 +275,7 @@ cat; meow; 1; ; true
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'split("; ")' sample.yml
|
||||
yq 'split("; ")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -287,7 +293,7 @@ word
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'split("; ")' sample.yml
|
||||
yq 'split("; ")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
The style operator can be used to get or set the style of nodes (e.g. string style, yaml style)
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Update and set style of a particular node (simple)
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -11,7 +17,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.b = "new" | .a.b style="double"' sample.yml
|
||||
yq '.a.b = "new" | .a.b style="double"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -29,7 +35,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'with(.a.b ; . = "new" | . style="double")' sample.yml
|
||||
yq 'with(.a.b ; . = "new" | . style="double")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -48,7 +54,7 @@ e: true
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.. style="tagged"' sample.yml
|
||||
yq '.. style="tagged"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -69,7 +75,7 @@ e: true
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.. style="double"' sample.yml
|
||||
yq '.. style="double"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -89,7 +95,7 @@ e: true
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '... style="double"' sample.yml
|
||||
yq '... style="double"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -109,7 +115,7 @@ e: true
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.. style="single"' sample.yml
|
||||
yq '.. style="single"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -129,7 +135,7 @@ e: true
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.. style="literal"' sample.yml
|
||||
yq '.. style="literal"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -153,7 +159,7 @@ e: true
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.. style="folded"' sample.yml
|
||||
yq '.. style="folded"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -177,7 +183,7 @@ e: true
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.. style="flow"' sample.yml
|
||||
yq '.. style="flow"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -196,7 +202,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '... style=""' sample.yml
|
||||
yq '... style=""' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -214,7 +220,7 @@ b: double
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] style |= .' sample.yml
|
||||
yq '.[] style |= .' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -229,7 +235,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.. | style' sample.yml
|
||||
yq '.. | style' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
|
||||
You can use subtract to subtract numbers, as well as removing elements from an array.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Array subtraction
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '[1,2] - [2,3]'
|
||||
yq --null-input '[1,2] - [2,3]'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -15,7 +21,7 @@ will output
|
||||
## Array subtraction with nested array
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '[[1], 1, 2] - [[1], 3]'
|
||||
yq --null-input '[[1], 1, 2] - [[1], 3]'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -34,7 +40,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '. - [{"c": "d", "a": "b"}]' sample.yml
|
||||
yq '. - [{"c": "d", "a": "b"}]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -51,7 +57,7 @@ b: 4.5
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = .a - .b' sample.yml
|
||||
yq '.a = .a - .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -69,7 +75,7 @@ b: 4.5
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = .a - .b' sample.yml
|
||||
yq '.a = .a - .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -87,7 +93,7 @@ b: 4
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = .a - .b' sample.yml
|
||||
yq '.a = .a - .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -103,7 +109,7 @@ b: 5
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] -= 1' sample.yml
|
||||
yq '.[] -= 1' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -111,3 +117,53 @@ a: 2
|
||||
b: 4
|
||||
```
|
||||
|
||||
## Date subtraction
|
||||
You can subtract durations from dates. Assumes RFC3339 date time format, see [date-time operators](https://mikefarah.gitbook.io/yq/operators/date-time-operators) for more information.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: 2021-01-01T03:10:00Z
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a -= "3h10m"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: 2021-01-01T00:00:00Z
|
||||
```
|
||||
|
||||
## Date subtraction - custom format
|
||||
Use with_dtf to specify your datetime format. See [date-time operators](https://mikefarah.gitbook.io/yq/operators/date-time-operators) for more information.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 6:00AM GMT
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq 'with_dtf("Monday, 02-Jan-06 at 3:04PM MST", .a -= "3h1m")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: Saturday, 15-Dec-01 at 2:59AM GMT
|
||||
```
|
||||
|
||||
## Custom types: that are really numbers
|
||||
When custom tags are encountered, yq will try to decode the underlying type.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: !horse 2
|
||||
b: !goat 1
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a -= .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: !horse 1
|
||||
b: !goat 1
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
The tag operator can be used to get or set the tag of nodes (e.g. `!!str`, `!!int`, `!!bool`).
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Get tag
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -13,7 +19,7 @@ f: []
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.. | tag' sample.yml
|
||||
yq '.. | tag' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -32,7 +38,7 @@ a: str
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a tag = "!!mikefarah"' sample.yml
|
||||
yq '.a tag = "!!mikefarah"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -49,7 +55,7 @@ e: true
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '(.. | select(tag == "!!int")) tag= "!!str"' sample.yml
|
||||
yq '(.. | select(tag == "!!int")) tag= "!!str"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
This is the simplest (and perhaps most used) operator, it is used to navigate deeply into yaml structures.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Simple map navigation
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -10,7 +16,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a' sample.yml
|
||||
yq '.a' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -27,7 +33,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[]' sample.yml
|
||||
yq '.[]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -44,7 +50,7 @@ cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[]' sample.yml
|
||||
yq '.[]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -59,7 +65,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.["{}"]' sample.yml
|
||||
yq '.["{}"]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -75,7 +81,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a["key.withdots"]["another.key"]' sample.yml
|
||||
yq '.a["key.withdots"]["another.key"]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -91,7 +97,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.["red rabbit"]' sample.yml
|
||||
yq '.["red rabbit"]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -109,7 +115,7 @@ banana: soft yum
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[.b]' sample.yml
|
||||
yq '.[.b]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -125,7 +131,7 @@ c: banana
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.b' sample.yml
|
||||
yq '.a.b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -143,7 +149,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a?' sample.yml
|
||||
yq '.a?' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -158,7 +164,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a."*a*"' sample.yml
|
||||
yq '.a."*a*"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -175,7 +181,7 @@ b: *cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.b' sample.yml
|
||||
yq '.b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -191,7 +197,7 @@ b: *cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.b[]' sample.yml
|
||||
yq '.b[]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -207,7 +213,7 @@ b: *cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.b.c' sample.yml
|
||||
yq '.b.c' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -223,7 +229,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[0]' sample.yml
|
||||
yq '.[0]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -237,7 +243,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[1][0]' sample.yml
|
||||
yq '.[1][0]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -251,7 +257,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[2]' sample.yml
|
||||
yq '.[2]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -265,7 +271,7 @@ a: b
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[0]' sample.yml
|
||||
yq '.[0]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -296,7 +302,7 @@ foobar:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.foobar.a' sample.yml
|
||||
yq '.foobar.a' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -327,7 +333,7 @@ foobar:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.foobar.c' sample.yml
|
||||
yq '.foobar.c' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -358,7 +364,7 @@ foobar:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.foobar.thing' sample.yml
|
||||
yq '.foobar.thing' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -389,7 +395,7 @@ foobar:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.foobar[]' sample.yml
|
||||
yq '.foobar[]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -424,7 +430,7 @@ foobar:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.foobarList.thing' sample.yml
|
||||
yq '.foobarList.thing' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -455,7 +461,7 @@ foobar:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.foobarList[]' sample.yml
|
||||
yq '.foobarList[]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -475,7 +481,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a[0, 2]' sample.yml
|
||||
yq '.a[0, 2]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
|
||||
This operator is used to combine different results together.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Combine scalars
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '1, true, "cat"'
|
||||
yq --null-input '1, true, "cat"'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -23,7 +29,7 @@ c: fieldC
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a, .c' sample.yml
|
||||
yq '.a, .c' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
This is used to filter out duplicated items in an array.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Unique array of scalars (string/numbers)
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -12,7 +18,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'unique' sample.yml
|
||||
yq 'unique' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -33,7 +39,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'unique' sample.yml
|
||||
yq 'unique' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -53,7 +59,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'unique_by(tag)' sample.yml
|
||||
yq 'unique_by(tag)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -72,7 +78,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'unique_by(.name)' sample.yml
|
||||
yq 'unique_by(.name)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -4,6 +4,12 @@ Like the `jq` equivalents, variables are sometimes required for the more complex
|
||||
|
||||
Note that there is also an additional `ref` operator that holds a reference (instead of a copy) of the path, allowing you to make multiple changes to the same path.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Single value variable
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -11,7 +17,7 @@ a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a as $foo | $foo' sample.yml
|
||||
yq '.a as $foo | $foo' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -26,7 +32,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] as $foo | $foo' sample.yml
|
||||
yq '.[] as $foo | $foo' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -50,7 +56,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.realnames as $names | .posts[] | {"title":.title, "author": $names[.author]}' sample.yml
|
||||
yq '.realnames as $names | .posts[] | {"title":.title, "author": $names[.author]}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -68,7 +74,7 @@ b: b_value
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a as $x | .b as $y | .b = $x | .a = $y' sample.yml
|
||||
yq '.a as $x | .b as $y | .b = $x | .a = $y' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -87,7 +93,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.b ref $x | $x = "new" | $x style="double"' sample.yml
|
||||
yq '.a.b ref $x | $x = "new" | $x style="double"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Use the `with` operator to conveniently make multiple updates to a deeply nested path, or to update array elements relatively to each other. The first argument expression sets the root context, and the second expression runs against that root context.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Update and style
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -11,7 +17,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'with(.a.deeply.nested; . = "newValue" | . style="single")' sample.yml
|
||||
yq 'with(.a.deeply.nested; . = "newValue" | . style="single")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -30,7 +36,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'with(.a.deeply; .nested = "newValue" | .other= "newThing")' sample.yml
|
||||
yq 'with(.a.deeply; .nested = "newValue" | .other= "newThing")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -51,7 +57,7 @@ myArray:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'with(.myArray[]; .b = .a + " yum")' sample.yml
|
||||
yq 'with(.myArray[]; .b = .a + " yum")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
# JSON
|
||||
|
||||
Encode and decode to and from JSON. Note that YAML is a _superset_ of JSON - so `yq` can read any json file without doing anything special.
|
||||
|
||||
This means you don't need to 'convert' a JSON file to YAML - however if you want idiomatic YAML styling, then you can use the `-P/--prettyPrint` flag, see examples below.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Parse json: simple
|
||||
JSON is a subset of yaml, so all you need to do is prettify the output
|
||||
|
||||
Given a sample.json file of:
|
||||
```json
|
||||
{"cat": "meow"}
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -P '.' sample.json
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cat: meow
|
||||
```
|
||||
|
||||
## Parse json: complex
|
||||
JSON is a subset of yaml, so all you need to do is prettify the output
|
||||
|
||||
Given a sample.json file of:
|
||||
```json
|
||||
{"a":"Easy! as one two three","b":{"c":2,"d":[3,4]}}
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -P '.' sample.json
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: Easy! as one two three
|
||||
b:
|
||||
c: 2
|
||||
d:
|
||||
- 3
|
||||
- 4
|
||||
```
|
||||
|
||||
## Encode json: simple
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
cat: meow
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -o=json '.' sample.yml
|
||||
```
|
||||
will output
|
||||
```json
|
||||
{
|
||||
"cat": "meow"
|
||||
}
|
||||
```
|
||||
|
||||
## Encode json: simple - in one line
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
cat: meow # this is a comment, and it will be dropped.
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -o=json -I=0 '.' sample.yml
|
||||
```
|
||||
will output
|
||||
```json
|
||||
{"cat":"meow"}
|
||||
```
|
||||
|
||||
## Encode json: comments
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
cat: meow # this is a comment, and it will be dropped.
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -o=json '.' sample.yml
|
||||
```
|
||||
will output
|
||||
```json
|
||||
{
|
||||
"cat": "meow"
|
||||
}
|
||||
```
|
||||
|
||||
## Encode json: anchors
|
||||
Anchors are dereferenced
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
cat: &ref meow
|
||||
anotherCat: *ref
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -o=json '.' sample.yml
|
||||
```
|
||||
will output
|
||||
```json
|
||||
{
|
||||
"cat": "meow",
|
||||
"anotherCat": "meow"
|
||||
}
|
||||
```
|
||||
|
||||
## Encode json: multiple results
|
||||
Each matching node is converted into a json doc. This is best used with 0 indent (json document per line)
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
things: [{stuff: cool}, {whatever: cat}]
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -o=json -I=0 '.things[]' sample.yml
|
||||
```
|
||||
will output
|
||||
```json
|
||||
{"stuff":"cool"}
|
||||
{"whatever":"cat"}
|
||||
```
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# JSON
|
||||
|
||||
Encode and decode to and from JSON. Note that YAML is a _superset_ of JSON - so `yq` can read any json file without doing anything special.
|
||||
|
||||
This means you don't need to 'convert' a JSON file to YAML - however if you want idiomatic YAML styling, then you can use the `-P/--prettyPrint` flag, see examples below.
|
||||
@@ -0,0 +1,5 @@
|
||||
# Properties
|
||||
|
||||
Encode to a property file (decode not yet supported). Line comments on value nodes will be copied across.
|
||||
|
||||
By default, empty maps and arrays are not encoded - see below for an example on how to encode a value for these.
|
||||
@@ -2,22 +2,6 @@
|
||||
|
||||
Encode and decode to and from XML. Whitespace is not conserved for round trips - but the order of the fields are.
|
||||
|
||||
As yaml does not have the concept of attributes, xml attributes are converted to regular fields with a prefix to prevent clobbering. This defaults to "+", use the `--xml-attribute-prefix` to change.
|
||||
|
||||
Consecutive xml nodes with the same name are assumed to be arrays.
|
||||
|
||||
All values in XML are assumed to be strings - but you can use `from_yaml` to parse them into their correct types:
|
||||
|
||||
|
||||
```
|
||||
yq e -p=xml '.myNumberField |= from_yaml' my.xml
|
||||
```
|
||||
|
||||
|
||||
XML nodes that have attributes then plain content, e.g:
|
||||
|
||||
```xml
|
||||
<cat name="tiger">meow</cat>
|
||||
```
|
||||
|
||||
The content of the node will be set as a field in the map with the key "+content". Use the `--xml-content-name` flag to change this.
|
||||
XML content data and attributes are created as fields. This can be controlled by the `'--xml-attribute-prefix` and `--xml-content-name` flags - see below for examples.
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
# Properties
|
||||
|
||||
Encode to a property file (decode not yet supported). Line comments on value nodes will be copied across.
|
||||
|
||||
By default, empty maps and arrays are not encoded - see below for an example on how to encode a value for these.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Encode properties
|
||||
Note that empty arrays and maps are not encoded by default.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
# block comments don't come through
|
||||
person: # neither do comments on maps
|
||||
name: Mike # comments on values appear
|
||||
pets:
|
||||
- cat # comments on array values appear
|
||||
food: [pizza] # comments on arrays do not
|
||||
emptyArray: []
|
||||
emptyMap: []
|
||||
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -o=props sample.yml
|
||||
```
|
||||
will output
|
||||
```properties
|
||||
# comments on values appear
|
||||
person.name = Mike
|
||||
|
||||
# comments on array values appear
|
||||
person.pets.0 = cat
|
||||
person.food.0 = pizza
|
||||
```
|
||||
|
||||
## Encode properties: no comments
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
# block comments don't come through
|
||||
person: # neither do comments on maps
|
||||
name: Mike # comments on values appear
|
||||
pets:
|
||||
- cat # comments on array values appear
|
||||
food: [pizza] # comments on arrays do not
|
||||
emptyArray: []
|
||||
emptyMap: []
|
||||
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -o=props '... comments = ""' sample.yml
|
||||
```
|
||||
will output
|
||||
```properties
|
||||
person.name = Mike
|
||||
person.pets.0 = cat
|
||||
person.food.0 = pizza
|
||||
```
|
||||
|
||||
## Encode properties: include empty maps and arrays
|
||||
Use a yq expression to set the empty maps and sequences to your desired value.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
# block comments don't come through
|
||||
person: # neither do comments on maps
|
||||
name: Mike # comments on values appear
|
||||
pets:
|
||||
- cat # comments on array values appear
|
||||
food: [pizza] # comments on arrays do not
|
||||
emptyArray: []
|
||||
emptyMap: []
|
||||
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -o=props '(.. | select( (tag == "!!map" or tag =="!!seq") and length == 0)) = ""' sample.yml
|
||||
```
|
||||
will output
|
||||
```properties
|
||||
# comments on values appear
|
||||
person.name = Mike
|
||||
|
||||
# comments on array values appear
|
||||
person.pets.0 = cat
|
||||
person.food.0 = pizza
|
||||
emptyArray =
|
||||
emptyMap =
|
||||
```
|
||||
|
||||
## Decode properties
|
||||
Given a sample.properties file of:
|
||||
```properties
|
||||
# comments on values appear
|
||||
person.name = Mike
|
||||
|
||||
# comments on array values appear
|
||||
person.pets.0 = cat
|
||||
person.food.0 = pizza
|
||||
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -p=props sample.properties
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
person:
|
||||
name: Mike # comments on values appear
|
||||
pets:
|
||||
- cat # comments on array values appear
|
||||
food:
|
||||
- pizza
|
||||
```
|
||||
|
||||
## Roundtrip
|
||||
Given a sample.properties file of:
|
||||
```properties
|
||||
# comments on values appear
|
||||
person.name = Mike
|
||||
|
||||
# comments on array values appear
|
||||
person.pets.0 = cat
|
||||
person.food.0 = pizza
|
||||
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -p=props -o=props '.person.pets.0 = "dog"' sample.properties
|
||||
```
|
||||
will output
|
||||
```properties
|
||||
# comments on values appear
|
||||
person.name = Mike
|
||||
|
||||
# comments on array values appear
|
||||
person.pets.0 = dog
|
||||
person.food.0 = pizza
|
||||
```
|
||||
|
||||
## Empty doc
|
||||
Given a sample.properties file of:
|
||||
```properties
|
||||
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -p=props sample.properties
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
```
|
||||
|
||||
+177
-35
@@ -2,39 +2,62 @@
|
||||
|
||||
Encode and decode to and from XML. Whitespace is not conserved for round trips - but the order of the fields are.
|
||||
|
||||
As yaml does not have the concept of attributes, xml attributes are converted to regular fields with a prefix to prevent clobbering. This defaults to "+", use the `--xml-attribute-prefix` to change.
|
||||
|
||||
Consecutive xml nodes with the same name are assumed to be arrays.
|
||||
|
||||
All values in XML are assumed to be strings - but you can use `from_yaml` to parse them into their correct types:
|
||||
XML content data and attributes are created as fields. This can be controlled by the `'--xml-attribute-prefix` and `--xml-content-name` flags - see below for examples.
|
||||
|
||||
{% hint style="warning" %}
|
||||
Note that versions prior to 4.18 require the 'eval/e' command to be specified. 
|
||||
|
||||
```
|
||||
yq e -p=xml '.myNumberField |= from_yaml' my.xml
|
||||
```
|
||||
|
||||
|
||||
XML nodes that have attributes then plain content, e.g:
|
||||
|
||||
```xml
|
||||
<cat name="tiger">meow</cat>
|
||||
```
|
||||
|
||||
The content of the node will be set as a field in the map with the key "+content". Use the `--xml-content-name` flag to change this.
|
||||
`yq e <exp> <file>`
|
||||
{% endhint %}
|
||||
|
||||
## Parse xml: simple
|
||||
Notice how all the values are strings, see the next example on how you can fix that.
|
||||
|
||||
Given a sample.xml file of:
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<cat>meow</cat>
|
||||
<cat>
|
||||
<says>meow</says>
|
||||
<legs>4</legs>
|
||||
<cute>true</cute>
|
||||
</cat>
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq e -p=xml '.' sample.xml
|
||||
yq -p=xml '.' sample.xml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cat: meow
|
||||
cat:
|
||||
says: meow
|
||||
legs: "4"
|
||||
cute: "true"
|
||||
```
|
||||
|
||||
## Parse xml: number
|
||||
All values are assumed to be strings when parsing XML, but you can use the `from_yaml` operator on all the strings values to autoparse into the correct type.
|
||||
|
||||
Given a sample.xml file of:
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<cat>
|
||||
<says>meow</says>
|
||||
<legs>4</legs>
|
||||
<cute>true</cute>
|
||||
</cat>
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -p=xml ' (.. | select(tag == "!!str")) |= from_yaml' sample.xml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cat:
|
||||
says: meow
|
||||
legs: 4
|
||||
cute: true
|
||||
```
|
||||
|
||||
## Parse xml: array
|
||||
@@ -43,22 +66,22 @@ Consecutive nodes with identical xml names are assumed to be arrays.
|
||||
Given a sample.xml file of:
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<animal>1</animal>
|
||||
<animal>2</animal>
|
||||
<animal>cat</animal>
|
||||
<animal>goat</animal>
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq e -p=xml '.' sample.xml
|
||||
yq -p=xml '.' sample.xml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
animal:
|
||||
- "1"
|
||||
- "2"
|
||||
- cat
|
||||
- goat
|
||||
```
|
||||
|
||||
## Parse xml: attributes
|
||||
Attributes are converted to fields, with the attribute prefix.
|
||||
Attributes are converted to fields, with the default attribute prefix '+'. Use '--xml-attribute-prefix` to set your own.
|
||||
|
||||
Given a sample.xml file of:
|
||||
```xml
|
||||
@@ -69,7 +92,7 @@ Given a sample.xml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq e -p=xml '.' sample.xml
|
||||
yq -p=xml '.' sample.xml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -79,7 +102,7 @@ cat:
|
||||
```
|
||||
|
||||
## Parse xml: attributes with content
|
||||
Content is added as a field, using the content name
|
||||
Content is added as a field, using the default content name of `+content`. Use `--xml-content-name` to set your own.
|
||||
|
||||
Given a sample.xml file of:
|
||||
```xml
|
||||
@@ -88,7 +111,7 @@ Given a sample.xml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq e -p=xml '.' sample.xml
|
||||
yq -p=xml '.' sample.xml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -97,6 +120,53 @@ cat:
|
||||
+legs: "4"
|
||||
```
|
||||
|
||||
## Parse xml: with comments
|
||||
A best attempt is made to preserve comments.
|
||||
|
||||
Given a sample.xml file of:
|
||||
```xml
|
||||
|
||||
<!-- before cat -->
|
||||
<cat>
|
||||
<!-- in cat before -->
|
||||
<x>3<!-- multi
|
||||
line comment
|
||||
for x --></x>
|
||||
<!-- before y -->
|
||||
<y>
|
||||
<!-- in y before -->
|
||||
<d><!-- in d before -->z<!-- in d after --></d>
|
||||
|
||||
<!-- in y after -->
|
||||
</y>
|
||||
<!-- in_cat_after -->
|
||||
</cat>
|
||||
<!-- after cat -->
|
||||
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -p=xml '.' sample.xml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
# before cat
|
||||
cat:
|
||||
# in cat before
|
||||
x: "3" # multi
|
||||
# line comment
|
||||
# for x
|
||||
# before y
|
||||
|
||||
y:
|
||||
# in y before
|
||||
# in d before
|
||||
d: z # in d after
|
||||
# in y after
|
||||
# in_cat_after
|
||||
# after cat
|
||||
```
|
||||
|
||||
## Encode xml: simple
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -104,11 +174,12 @@ cat: purrs
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq e -o=xml '.' sample.yml
|
||||
yq -o=xml '.' sample.yml
|
||||
```
|
||||
will output
|
||||
```xml
|
||||
<cat>purrs</cat>```
|
||||
<cat>purrs</cat>
|
||||
```
|
||||
|
||||
## Encode xml: array
|
||||
Given a sample.yml file of:
|
||||
@@ -120,14 +191,15 @@ pets:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq e -o=xml '.' sample.yml
|
||||
yq -o=xml '.' sample.yml
|
||||
```
|
||||
will output
|
||||
```xml
|
||||
<pets>
|
||||
<cat>purrs</cat>
|
||||
<cat>meows</cat>
|
||||
</pets>```
|
||||
</pets>
|
||||
```
|
||||
|
||||
## Encode xml: attributes
|
||||
Fields with the matching xml-attribute-prefix are assumed to be attributes.
|
||||
@@ -141,13 +213,14 @@ cat:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq e -o=xml '.' sample.yml
|
||||
yq -o=xml '.' sample.yml
|
||||
```
|
||||
will output
|
||||
```xml
|
||||
<cat name="tiger">
|
||||
<meows>true</meows>
|
||||
</cat>```
|
||||
</cat>
|
||||
```
|
||||
|
||||
## Encode xml: attributes with content
|
||||
Fields with the matching xml-content-name is assumed to be content.
|
||||
@@ -161,9 +234,78 @@ cat:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq e -o=xml '.' sample.yml
|
||||
yq -o=xml '.' sample.yml
|
||||
```
|
||||
will output
|
||||
```xml
|
||||
<cat name="tiger">cool</cat>```
|
||||
<cat name="tiger">cool</cat>
|
||||
```
|
||||
|
||||
## Encode xml: comments
|
||||
A best attempt is made to copy comments to xml.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
# above_cat
|
||||
cat: # inline_cat
|
||||
# above_array
|
||||
array: # inline_array
|
||||
- val1 # inline_val1
|
||||
# above_val2
|
||||
- val2 # inline_val2
|
||||
# below_cat
|
||||
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -o=xml '.' sample.yml
|
||||
```
|
||||
will output
|
||||
```xml
|
||||
<!-- above_cat inline_cat --><cat><!-- above_array inline_array -->
|
||||
<array>val1<!-- inline_val1 --></array>
|
||||
<array><!-- above_val2 -->val2<!-- inline_val2 --></array>
|
||||
</cat><!-- below_cat -->
|
||||
```
|
||||
|
||||
## Round trip: with comments
|
||||
A best effort is made, but comment positions and white space are not preserved perfectly.
|
||||
|
||||
Given a sample.xml file of:
|
||||
```xml
|
||||
|
||||
<!-- before cat -->
|
||||
<cat>
|
||||
<!-- in cat before -->
|
||||
<x>3<!-- multi
|
||||
line comment
|
||||
for x --></x>
|
||||
<!-- before y -->
|
||||
<y>
|
||||
<!-- in y before -->
|
||||
<d><!-- in d before -->z<!-- in d after --></d>
|
||||
|
||||
<!-- in y after -->
|
||||
</y>
|
||||
<!-- in_cat_after -->
|
||||
</cat>
|
||||
<!-- after cat -->
|
||||
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq -p=xml -o=xml '.' sample.xml
|
||||
```
|
||||
will output
|
||||
```xml
|
||||
<!-- before cat --><cat><!-- in cat before -->
|
||||
<x>3<!-- multi
|
||||
line comment
|
||||
for x --></x><!-- before y -->
|
||||
<y><!-- in y before
|
||||
in d before -->
|
||||
<d>z<!-- in d after --></d><!-- in y after -->
|
||||
</y><!-- in_cat_after -->
|
||||
</cat><!-- after cat -->
|
||||
```
|
||||
|
||||
|
||||
+4
-86
@@ -11,92 +11,10 @@ import (
|
||||
)
|
||||
|
||||
type Encoder interface {
|
||||
Encode(node *yaml.Node) error
|
||||
}
|
||||
|
||||
type yamlEncoder struct {
|
||||
destination io.Writer
|
||||
indent int
|
||||
colorise bool
|
||||
firstDoc bool
|
||||
}
|
||||
|
||||
func NewYamlEncoder(destination io.Writer, indent int, colorise bool) Encoder {
|
||||
if indent < 0 {
|
||||
indent = 0
|
||||
}
|
||||
return &yamlEncoder{destination, indent, colorise, true}
|
||||
}
|
||||
|
||||
func (ye *yamlEncoder) Encode(node *yaml.Node) error {
|
||||
|
||||
destination := ye.destination
|
||||
tempBuffer := bytes.NewBuffer(nil)
|
||||
if ye.colorise {
|
||||
destination = tempBuffer
|
||||
}
|
||||
|
||||
var encoder = yaml.NewEncoder(destination)
|
||||
|
||||
encoder.SetIndent(ye.indent)
|
||||
// TODO: work out if the first doc had a separator or not.
|
||||
if ye.firstDoc {
|
||||
ye.firstDoc = false
|
||||
} else if _, err := destination.Write([]byte("---\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := encoder.Encode(node); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ye.colorise {
|
||||
return colorizeAndPrint(tempBuffer.Bytes(), ye.destination)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type jsonEncoder struct {
|
||||
encoder *json.Encoder
|
||||
}
|
||||
|
||||
func mapKeysToStrings(node *yaml.Node) {
|
||||
|
||||
if node.Kind == yaml.MappingNode {
|
||||
for index, child := range node.Content {
|
||||
if index%2 == 0 { // its a map key
|
||||
child.Tag = "!!str"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, child := range node.Content {
|
||||
mapKeysToStrings(child)
|
||||
}
|
||||
}
|
||||
|
||||
func NewJsonEncoder(destination io.Writer, indent int) Encoder {
|
||||
var encoder = json.NewEncoder(destination)
|
||||
encoder.SetEscapeHTML(false) // do not escape html chars e.g. &, <, >
|
||||
|
||||
var indentString = ""
|
||||
|
||||
for index := 0; index < indent; index++ {
|
||||
indentString = indentString + " "
|
||||
}
|
||||
encoder.SetIndent("", indentString)
|
||||
return &jsonEncoder{encoder}
|
||||
}
|
||||
|
||||
func (je *jsonEncoder) Encode(node *yaml.Node) error {
|
||||
var dataBucket orderedMap
|
||||
// firstly, convert all map keys to strings
|
||||
mapKeysToStrings(node)
|
||||
errorDecoding := node.Decode(&dataBucket)
|
||||
if errorDecoding != nil {
|
||||
return errorDecoding
|
||||
}
|
||||
return je.encoder.Encode(dataBucket)
|
||||
Encode(writer io.Writer, node *yaml.Node) error
|
||||
PrintDocumentSeparator(writer io.Writer) error
|
||||
PrintLeadingContent(writer io.Writer, content string) error
|
||||
CanHandleAliases() bool
|
||||
}
|
||||
|
||||
// orderedMap allows to marshal and unmarshal JSON and YAML values keeping the
|
||||
|
||||
+23
-10
@@ -9,16 +9,26 @@ import (
|
||||
)
|
||||
|
||||
type csvEncoder struct {
|
||||
destination csv.Writer
|
||||
separator rune
|
||||
}
|
||||
|
||||
func NewCsvEncoder(destination io.Writer, separator rune) Encoder {
|
||||
csvWriter := *csv.NewWriter(destination)
|
||||
csvWriter.Comma = separator
|
||||
return &csvEncoder{csvWriter}
|
||||
func NewCsvEncoder(separator rune) Encoder {
|
||||
return &csvEncoder{separator}
|
||||
}
|
||||
|
||||
func (e *csvEncoder) encodeRow(contents []*yaml.Node) error {
|
||||
func (e *csvEncoder) CanHandleAliases() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *csvEncoder) PrintDocumentSeparator(writer io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *csvEncoder) PrintLeadingContent(writer io.Writer, content string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *csvEncoder) encodeRow(csvWriter *csv.Writer, contents []*yaml.Node) error {
|
||||
stringValues := make([]string, len(contents))
|
||||
|
||||
for i, child := range contents {
|
||||
@@ -28,10 +38,13 @@ func (e *csvEncoder) encodeRow(contents []*yaml.Node) error {
|
||||
}
|
||||
stringValues[i] = child.Value
|
||||
}
|
||||
return e.destination.Write(stringValues)
|
||||
return csvWriter.Write(stringValues)
|
||||
}
|
||||
|
||||
func (e *csvEncoder) Encode(originalNode *yaml.Node) error {
|
||||
func (e *csvEncoder) Encode(writer io.Writer, originalNode *yaml.Node) error {
|
||||
csvWriter := csv.NewWriter(writer)
|
||||
csvWriter.Comma = e.separator
|
||||
|
||||
// node must be a sequence
|
||||
node := unwrapDoc(originalNode)
|
||||
if node.Kind != yaml.SequenceNode {
|
||||
@@ -40,7 +53,7 @@ func (e *csvEncoder) Encode(originalNode *yaml.Node) error {
|
||||
return nil
|
||||
}
|
||||
if node.Content[0].Kind == yaml.ScalarNode {
|
||||
return e.encodeRow(node.Content)
|
||||
return e.encodeRow(csvWriter, node.Content)
|
||||
}
|
||||
|
||||
for i, child := range node.Content {
|
||||
@@ -48,7 +61,7 @@ func (e *csvEncoder) Encode(originalNode *yaml.Node) error {
|
||||
if child.Kind != yaml.SequenceNode {
|
||||
return fmt.Errorf("csv encoding only works for arrays of scalars (string/numbers/booleans), child[%v] is a %v", i, child.Tag)
|
||||
}
|
||||
err := e.encodeRow(child.Content)
|
||||
err := e.encodeRow(csvWriter, child.Content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@ func yamlToCsv(sampleYaml string, separator rune) string {
|
||||
var output bytes.Buffer
|
||||
writer := bufio.NewWriter(&output)
|
||||
|
||||
var jsonEncoder = NewCsvEncoder(writer, separator)
|
||||
var jsonEncoder = NewCsvEncoder(separator)
|
||||
inputs, err := readDocuments(strings.NewReader(sampleYaml), "sample.yml", 0, NewYamlDecoder())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
node := inputs.Front().Value.(*CandidateNode).Node
|
||||
err = jsonEncoder.Encode(node)
|
||||
err = jsonEncoder.Encode(writer, node)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type jsonEncoder struct {
|
||||
indentString string
|
||||
}
|
||||
|
||||
func mapKeysToStrings(node *yaml.Node) {
|
||||
|
||||
if node.Kind == yaml.MappingNode {
|
||||
for index, child := range node.Content {
|
||||
if index%2 == 0 { // its a map key
|
||||
child.Tag = "!!str"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, child := range node.Content {
|
||||
mapKeysToStrings(child)
|
||||
}
|
||||
}
|
||||
|
||||
func NewJONEncoder(indent int) Encoder {
|
||||
var indentString = ""
|
||||
|
||||
for index := 0; index < indent; index++ {
|
||||
indentString = indentString + " "
|
||||
}
|
||||
|
||||
return &jsonEncoder{indentString}
|
||||
}
|
||||
|
||||
func (je *jsonEncoder) CanHandleAliases() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (je *jsonEncoder) PrintDocumentSeparator(writer io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (je *jsonEncoder) PrintLeadingContent(writer io.Writer, content string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (je *jsonEncoder) Encode(writer io.Writer, node *yaml.Node) error {
|
||||
var encoder = json.NewEncoder(writer)
|
||||
encoder.SetEscapeHTML(false) // do not escape html chars e.g. &, <, >
|
||||
encoder.SetIndent("", je.indentString)
|
||||
|
||||
var dataBucket orderedMap
|
||||
// firstly, convert all map keys to strings
|
||||
mapKeysToStrings(node)
|
||||
errorDecoding := node.Decode(&dataBucket)
|
||||
if errorDecoding != nil {
|
||||
return errorDecoding
|
||||
}
|
||||
return encoder.Encode(dataBucket)
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
@@ -10,14 +12,54 @@ import (
|
||||
)
|
||||
|
||||
type propertiesEncoder struct {
|
||||
destination io.Writer
|
||||
}
|
||||
|
||||
func NewPropertiesEncoder(destination io.Writer) Encoder {
|
||||
return &propertiesEncoder{destination}
|
||||
func NewPropertiesEncoder() Encoder {
|
||||
return &propertiesEncoder{}
|
||||
}
|
||||
|
||||
func (pe *propertiesEncoder) Encode(node *yaml.Node) error {
|
||||
func (pe *propertiesEncoder) CanHandleAliases() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (pe *propertiesEncoder) PrintDocumentSeparator(writer io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pe *propertiesEncoder) PrintLeadingContent(writer io.Writer, content string) error {
|
||||
reader := bufio.NewReader(strings.NewReader(content))
|
||||
for {
|
||||
|
||||
readline, errReading := reader.ReadString('\n')
|
||||
if errReading != nil && !errors.Is(errReading, io.EOF) {
|
||||
return errReading
|
||||
}
|
||||
if strings.Contains(readline, "$yqDocSeperator$") {
|
||||
|
||||
if err := pe.PrintDocumentSeparator(writer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} else {
|
||||
if err := writeString(writer, readline); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if errors.Is(errReading, io.EOF) {
|
||||
if readline != "" {
|
||||
// the last comment we read didn't have a new line, put one in
|
||||
if err := writeString(writer, "\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pe *propertiesEncoder) Encode(writer io.Writer, node *yaml.Node) error {
|
||||
mapKeysToStrings(node)
|
||||
p := properties.NewProperties()
|
||||
err := pe.doEncode(p, node, "")
|
||||
@@ -25,14 +67,12 @@ func (pe *propertiesEncoder) Encode(node *yaml.Node) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = p.WriteComment(pe.destination, "#", properties.UTF8)
|
||||
_, err = p.WriteComment(writer, "#", properties.UTF8)
|
||||
return err
|
||||
}
|
||||
|
||||
func (pe *propertiesEncoder) doEncode(p *properties.Properties, node *yaml.Node, path string) error {
|
||||
p.SetComment(path,
|
||||
strings.Replace(node.HeadComment, "#", "", 1)+
|
||||
strings.Replace(node.LineComment, "#", "", 1))
|
||||
p.SetComment(path, headAndLineComment(node))
|
||||
switch node.Kind {
|
||||
case yaml.ScalarNode:
|
||||
_, _, err := p.Set(path, node.Value)
|
||||
|
||||
@@ -13,13 +13,13 @@ func yamlToProps(sampleYaml string) string {
|
||||
var output bytes.Buffer
|
||||
writer := bufio.NewWriter(&output)
|
||||
|
||||
var propsEncoder = NewPropertiesEncoder(writer)
|
||||
var propsEncoder = NewPropertiesEncoder()
|
||||
inputs, err := readDocuments(strings.NewReader(sampleYaml), "sample.yml", 0, NewYamlDecoder())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
node := inputs.Front().Value.(*CandidateNode).Node
|
||||
err = propsEncoder.Encode(node)
|
||||
err = propsEncoder.Encode(writer, node)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -31,18 +31,18 @@ func yamlToProps(sampleYaml string) string {
|
||||
func TestPropertiesEncoderSimple(t *testing.T) {
|
||||
var sampleYaml = `a: 'bob cool'`
|
||||
|
||||
var expectedJson = `a = bob cool`
|
||||
var expectedProps = `a = bob cool`
|
||||
var actualProps = yamlToProps(sampleYaml)
|
||||
test.AssertResult(t, expectedJson, actualProps)
|
||||
test.AssertResult(t, expectedProps, actualProps)
|
||||
}
|
||||
|
||||
func TestPropertiesEncoderSimpleWithComments(t *testing.T) {
|
||||
var sampleYaml = `a: 'bob cool' # line`
|
||||
|
||||
var expectedJson = `# line
|
||||
var expectedProps = `# line
|
||||
a = bob cool`
|
||||
var actualProps = yamlToProps(sampleYaml)
|
||||
test.AssertResult(t, expectedJson, actualProps)
|
||||
test.AssertResult(t, expectedProps, actualProps)
|
||||
}
|
||||
|
||||
func TestPropertiesEncoderDeep(t *testing.T) {
|
||||
@@ -50,9 +50,9 @@ func TestPropertiesEncoderDeep(t *testing.T) {
|
||||
b: "bob cool"
|
||||
`
|
||||
|
||||
var expectedJson = `a.b = bob cool`
|
||||
var expectedProps = `a.b = bob cool`
|
||||
var actualProps = yamlToProps(sampleYaml)
|
||||
test.AssertResult(t, expectedJson, actualProps)
|
||||
test.AssertResult(t, expectedProps, actualProps)
|
||||
}
|
||||
|
||||
func TestPropertiesEncoderDeepWithComments(t *testing.T) {
|
||||
@@ -60,10 +60,10 @@ func TestPropertiesEncoderDeepWithComments(t *testing.T) {
|
||||
b: "bob cool" # b thing
|
||||
`
|
||||
|
||||
var expectedJson = `# b thing
|
||||
var expectedProps = `# b thing
|
||||
a.b = bob cool`
|
||||
var actualProps = yamlToProps(sampleYaml)
|
||||
test.AssertResult(t, expectedJson, actualProps)
|
||||
test.AssertResult(t, expectedProps, actualProps)
|
||||
}
|
||||
|
||||
func TestPropertiesEncoderArray(t *testing.T) {
|
||||
@@ -71,8 +71,8 @@ func TestPropertiesEncoderArray(t *testing.T) {
|
||||
b: [{c: dog}, {c: cat}]
|
||||
`
|
||||
|
||||
var expectedJson = `a.b.0.c = dog
|
||||
var expectedProps = `a.b.0.c = dog
|
||||
a.b.1.c = cat`
|
||||
var actualProps = yamlToProps(sampleYaml)
|
||||
test.AssertResult(t, expectedJson, actualProps)
|
||||
test.AssertResult(t, expectedProps, actualProps)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user