Compare commits

..
1 Commits
Author SHA1 Message Date
Mike Farah d1adb48674 Added XML decoder 2021-12-21 14:59:01 +11:00
209 changed files with 1485 additions and 7668 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ country: Australia
And we run a command:
```bash
yq 'predictWeatherOf(.country)'
yq eval 'predictWeatherOf(.country)'
```
it could output
+1 -2
View File
@@ -14,7 +14,7 @@ jobs:
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Get dependencies
run: |
@@ -25,7 +25,6 @@ jobs:
fi
- name: Check the build
shell: bash -l {0}
run: |
export PATH=${PATH}:`go env GOPATH`/bin
scripts/devtools.sh
+2 -2
View File
@@ -8,7 +8,7 @@ jobs:
publishGitRelease:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '^1.17.5'
@@ -66,7 +66,7 @@ jobs:
IMAGE_NAME: mikefarah/yq
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
+1 -1
View File
@@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Get test
uses: mikefarah/yq@master
with:
+1 -5
View File
@@ -48,8 +48,4 @@ test*.yml
# man page
man.md
yq.1
# debian pkg
_build
debian/files
yq.1
-8
View File
@@ -18,14 +18,6 @@ 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:
+39 -102
View File
@@ -3,67 +3,40 @@
![Build](https://github.com/mikefarah/yq/workflows/Build/badge.svg) ![Docker Pulls](https://img.shields.io/docker/pulls/mikefarah/yq.svg) ![Github Releases (by Release)](https://img.shields.io/github/downloads/mikefarah/yq/total.svg) ![Go Report](https://goreportcard.com/badge/github.com/mikefarah/yq)
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.
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.
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 longer 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 one or more 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 '.a.b[0].c' file.yaml
yq e '.a.b[0].c' file.yaml
```
Pipe from STDIN:
```bash
cat file.yaml | yq '.a.b[0].c'
cat file.yaml | yq e '.a.b[0].c' -
```
Update a yaml file, inplace
```bash
yq -i '.a.b[0].c = "cool"' file.yaml
yq e -i '.a.b[0].c = "cool"' file.yaml
```
Update using environment variables
```bash
NAME=mike yq -i '.a.b[0].c = strenv(NAME)' file.yaml
NAME=mike yq e -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 -i '
yq e -i '
.a.b[0].c = "cool" |
.x.y.z = "foobar" |
.person.name = strenv(NAME)
@@ -109,32 +82,30 @@ 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 '.a.path'
sudo cat /etc/myfile | yq e '.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 '.a.path = "value"' | sudo sponge /etc/myfile
sudo cat /etc/myfile | yq e '.a.path = "value"' - | sudo sponge /etc/myfile
```
or write to a temporary file:
```
sudo cat /etc/myfile | yq '.a.path = "value"' | sudo tee /etc/myfile.tmp
sudo cat /etc/myfile | yq e '.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:
@@ -142,11 +113,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 '.this.thing'
cat myfile.yml | docker run -i --rm mikefarah/yq e . -
```
```bash
cat myfile.yml | podman run -i --rm mikefarah/yq '.this.thing'
cat myfile.yml | podman run -i --rm mikefarah/yq e . -
```
#### Run commands interactively:
@@ -193,28 +164,16 @@ Or, in your Dockerfile:
FROM mikefarah/yq
USER root
RUN apk add --no-cache bash
RUN apk add 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 -i '.foo.bar = "cool"' 'config.yml'
cmd: yq eval -i '.foo.bar = "cool"' 'config.yml'
```
See https://mikefarah.gitbook.io/yq/usage/github-action for more.
@@ -236,12 +195,6 @@ webi yq
See [webi](https://webinstall.dev/)
Supported by @adithyasunil26 (https://github.com/webinstall/webi-installers/tree/master/yq)
### Arch Linux
```
pacman -S go-yq
```
### Windows:
[![Chocolatey](https://img.shields.io/chocolatey/v/yq.svg)](https://chocolatey.org/packages/yq)
[![Chocolatey](https://img.shields.io/chocolatey/dt/yq.svg)](https://chocolatey.org/packages/yq)
@@ -279,23 +232,20 @@ 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, [JSON](https://mikefarah.gitbook.io/yq/usage/convert) and [XML](https://mikefarah.gitbook.io/yq/usage/xml) files
- Uses similar syntax as `jq` but works with YAML and JSON 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
- [Date/Time manipulation and formatting with TZ](https://mikefarah.gitbook.io/yq/operators/datetime)
- [Deeply data structures](https://mikefarah.gitbook.io/yq/operators/traverse-read)
- [Sort keys](https://mikefarah.gitbook.io/yq/operators/sort-keys)
- [Deeply traverse yaml](https://mikefarah.gitbook.io/yq/operators/traverse-read)
- [Sort yaml by 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 inplace](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate#flags)
- [Update yaml 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)
- [Decode/Encode base64 data](https://mikefarah.gitbook.io/yq/operators/encode-decode)
- [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/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)
- [Convert to properties](https://mikefarah.gitbook.io/yq/v/v4.x/usage/properties)
- [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.
- [Github Action](https://mikefarah.gitbook.io/yq/usage/github-action) to use in your automated pipeline (thanks @devorbitus)
@@ -309,41 +259,28 @@ 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:
completion Generate the autocompletion script for the specified shell
eval (default) Apply the expression to each document in each yaml file in sequence
eval 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 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")
-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
Use "yq [command] --help" for more information about a command.
```
+2 -168
View File
@@ -1,163 +1,12 @@
#!/bin/bash
setUp() {
rm test*.yml 2>/dev/null || true
rm .xyz 2>/dev/null || true
rm instructions.txt 2>/dev/null || true
rm test*.yml || 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"
}
testBasicExpressionFromFile() {
./yq -n ".xyz = 123" > test.yml
echo '.xyz = "meow" | .cool = "frog"' > instructions.txt
X=$(./yq --from-file instructions.txt test.yml -o=j -I=0)
assertEquals '{"xyz":"meow","cool":"frog"}' "$X"
X=$(./yq ea --from-file instructions.txt test.yml -o=j -I=0)
assertEquals '{"xyz":"meow","cool":"frog"}' "$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"
}
# when given a file, don't read STDIN
# otherwise strange things start happening
# in scripts
# https://github.com/mikefarah/yq/issues/1115
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)
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)
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)
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)
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=$(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")
X=$(./yq e '.a' test.yml)
assertEquals 123 "$X"
}
@@ -170,15 +19,6 @@ 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
@@ -200,12 +40,6 @@ 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
---
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
testCompletionRuns() {
result=$(./yq __complete "" 2>&1)
assertEquals 0 $?
assertContains "$result" "Completion ended with directive:"
}
source ./scripts/shunit2
-79
View File
@@ -1,79 +0,0 @@
#!/bin/bash
setUp() {
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() {
cat >test.yml <<EOL
<cat legs="4">BiBi</cat>
EOL
read -r -d '' expected << EOM
cat:
+content: BiBi
+legs: "4"
EOM
X=$(./yq e -p=xml test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea -p=xml test.yml)
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
-61
View File
@@ -102,65 +102,4 @@ EOM
assertEquals "$expected" "$X"
}
testOutputXml() {
cat >test.yml <<EOL
a: {b: {c: ["cat"]}}
EOL
read -r -d '' expected << EOM
<a>
<b>
<c>cat</c>
</b>
</a>
EOM
X=$(./yq e --output-format=xml test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea --output-format=xml test.yml)
assertEquals "$expected" "$X"
}
testOutputXmlShort() {
cat >test.yml <<EOL
a: {b: {c: ["cat"]}}
EOL
read -r -d '' expected << EOM
<a>
<b>
<c>cat</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"
}
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
-70
View File
@@ -1,70 +0,0 @@
#!/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
+83
View File
@@ -0,0 +1,83 @@
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.")
// }
// }
-4
View File
@@ -28,7 +28,3 @@ var frontMatter = ""
var splitFileExp = ""
var completedSuccessfully = false
var forceExpression = ""
var expressionFile = ""
+13 -38
View File
@@ -39,7 +39,7 @@ Note that it consumes more memory than eval.
}
return cmdEvalAll
}
func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
func evaluateAll(cmd *cobra.Command, args []string) error {
// 0 args, read std in
// 1 arg, null input, process expression
// 1 arg, read file in sequence
@@ -54,22 +54,6 @@ 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()
@@ -83,11 +67,7 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
}
// need to indirectly call the function so that completedSuccessfully is
// passed when we finish execution as opposed to now
defer func() {
if cmdError == nil {
cmdError = writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully)
}
}()
defer func() { writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully) }()
}
format, err := yqlib.OutputFormatFromString(outputFormat)
@@ -100,13 +80,9 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
return err
}
printerWriter, err := configurePrinterWriter(format, out)
if err != nil {
return err
}
encoder := configureEncoder(format)
printerWriter := configurePrinterWriter(format, out)
printer := yqlib.NewPrinter(encoder, printerWriter)
printer := yqlib.NewPrinter(printerWriter, format, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
if frontMatter != "" {
frontMatterHandler := yqlib.NewFrontMatterHandler(args[firstFileIndex])
@@ -125,23 +101,22 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
}
allAtOnceEvaluator := yqlib.NewAllAtOnceEvaluator()
expression, args, err := processArgs(pipingStdIn, args)
if err != nil {
return err
}
yqlib.GetLogger().Debugf("processed args: %v", args)
switch len(args) {
case 0:
if nullInput {
err = yqlib.NewStreamEvaluator().EvaluateNew(processExpression(expression), printer, "")
if pipingStdIn {
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer, leadingContentPreProcessing, decoder)
} 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(expression), args, printer, leadingContentPreProcessing, decoder)
err = allAtOnceEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer, leadingContentPreProcessing, decoder)
}
completedSuccessfully = err == nil
+18 -45
View File
@@ -13,7 +13,7 @@ func createEvaluateSequenceCommand() *cobra.Command {
var cmdEvalSequence = &cobra.Command{
Use: "eval [expression] [yaml_file1]...",
Aliases: []string{"e"},
Short: "(default) Apply the expression to each document in each yaml file in sequence",
Short: "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,16 +44,16 @@ 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 yqlib.PrettyPrintExp
return prettyPrintExp
} else if prettyPrint {
return fmt.Sprintf("%v | %v", expression, yqlib.PrettyPrintExp)
return fmt.Sprintf("%v | %v", expression, prettyPrintExp)
}
return expression
}
func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
func evaluateSequence(cmd *cobra.Command, args []string) error {
// 0 args, read std in
// 1 arg, null input, process expression
// 1 arg, read file in sequence
@@ -67,27 +67,6 @@ 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()
@@ -101,11 +80,7 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
}
// need to indirectly call the function so that completedSuccessfully is
// passed when we finish execution as opposed to now
defer func() {
if cmdError == nil {
cmdError = writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully)
}
}()
defer func() { writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully) }()
}
format, err := yqlib.OutputFormatFromString(outputFormat)
@@ -113,22 +88,18 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
return err
}
printerWriter, err := configurePrinterWriter(format, out)
if err != nil {
return err
}
encoder := configureEncoder(format)
printerWriter := configurePrinterWriter(format, out)
printer := yqlib.NewPrinter(encoder, printerWriter)
printer := yqlib.NewPrinter(printerWriter, format, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
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 {
@@ -143,21 +114,23 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
}
defer frontMatterHandler.CleanUp()
}
expression, args, err := processArgs(pipingStdIn, args)
if err != nil {
return err
}
switch len(args) {
case 0:
if nullInput {
err = streamEvaluator.EvaluateNew(processExpression(expression), printer, "")
if pipingStdIn {
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer, leadingContentPreProcessing, decoder)
} 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(expression), args, printer, leadingContentPreProcessing, decoder)
err = streamEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer, leadingContentPreProcessing, decoder)
}
completedSuccessfully = err == nil
+7 -24
View File
@@ -3,7 +3,6 @@ package cmd
import (
"os"
"github.com/mikefarah/yq/v4/pkg/yqlib"
"github.com/spf13/cobra"
logging "gopkg.in/op/go-logging.v1"
)
@@ -14,27 +13,17 @@ 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
}
return evaluateSequence(cmd, args)
cmd.Println(cmd.UsageString())
return nil
},
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}`,
)
@@ -48,9 +37,6 @@ yq -i '.stuff = "foo"' myfile.yml # update myfile.yml inplace
}
logging.SetBackend(backend)
yqlib.InitExpressionParser()
yqlib.XMLPreferences.AttributePrefix = xmlAttributePrefix
yqlib.XMLPreferences.ContentName = xmlContentName
},
}
@@ -62,18 +48,18 @@ yq -i '.stuff = "foo"' myfile.yml # update myfile.yml inplace
panic(err)
}
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|props|p|xml|x] parse format for input. Note that json is a subset of yaml.")
rootCmd.PersistentFlags().StringVarP(&outputFormat, "output-format", "o", "yaml", "[yaml|y|json|j|props|p] output format type.")
rootCmd.PersistentFlags().StringVarP(&inputFormat, "input-format", "p", "yaml", "[yaml|y|xml|x] input format type.")
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).")
rootCmd.PersistentFlags().BoolVarP(&nullInput, "null-input", "n", false, "Don't read input, simply evaluate the expression given. Useful for creating docs from scratch.")
rootCmd.PersistentFlags().BoolVarP(&nullInput, "null-input", "n", false, "Don't read input, simply evaluate the expression given. Useful for creating yaml docs from scratch.")
rootCmd.PersistentFlags().BoolVarP(&noDocSeparators, "no-doc", "N", false, "Don't print document separators (---)")
rootCmd.PersistentFlags().IntVarP(&indent, "indent", "I", 2, "sets indent level for output")
rootCmd.Flags().BoolVarP(&version, "version", "V", false, "Print version information and quit")
rootCmd.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the file inplace of first file given.")
rootCmd.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace of first yaml file given.")
rootCmd.PersistentFlags().BoolVarP(&unwrapScalar, "unwrapScalar", "", true, "unwrap scalar, print the value with no quotes, colors or comments")
rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print, shorthand for '... style = \"\"'")
rootCmd.PersistentFlags().BoolVarP(&exitStatus, "exit-status", "e", false, "set exit status if there are no matches or null or false is returned")
@@ -81,13 +67,10 @@ yq -i '.stuff = "foo"' myfile.yml # update myfile.yml inplace
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().BoolVarP(&leadingContentPreProcessing, "header-preprocess", "", true, "Slurp any header comments and separators before processing expression. This is a workaround for go-yaml to persist header content properly.")
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.")
rootCmd.PersistentFlags().StringVarP(&expressionFile, "from-file", "", "", "Load expression from specified file.")
rootCmd.AddCommand(
createEvaluateSequenceCommand(),
createEvaluateAllCommand(),
+6 -89
View File
@@ -7,7 +7,6 @@ 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) {
@@ -52,107 +51,25 @@ func configureDecoder() (yqlib.Decoder, error) {
return nil, err
}
switch yqlibInputFormat {
case yqlib.XMLInputFormat:
return yqlib.NewXMLDecoder(xmlAttributePrefix, xmlContentName), nil
case yqlib.PropertiesInputFormat:
return yqlib.NewPropertiesDecoder(), nil
case yqlib.XmlInputFormat:
return yqlib.NewXmlDecoder(xmlAttributePrefix, xmlContentName), nil
}
return yqlib.NewYamlDecoder(), nil
}
func configurePrinterWriter(format yqlib.PrinterOutputFormat, out io.Writer) (yqlib.PrinterWriter, error) {
func configurePrinterWriter(format yqlib.PrinterOutputFormat, out io.Writer) yqlib.PrinterWriter {
var printerWriter yqlib.PrinterWriter
if splitFileExp != "" {
colorsEnabled = forceColor
splitExp, err := yqlib.ExpressionParser.ParseExpression(splitFileExp)
splitExp, err := yqlib.NewExpressionParser().ParseExpression(splitFileExp)
if err != nil {
return nil, fmt.Errorf("bad split document expression: %w", err)
return nil
}
printerWriter = yqlib.NewMultiPrinterWriter(splitExp, format)
} else {
printerWriter = yqlib.NewSinglePrinterWriter(out)
}
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 we've been given a file, don't automatically
// read from stdin.
// this happens if there is more than one argument
// or only one argument and its a file
if !pipingStdin || len(args) > 1 || (len(args) > 0 && maybeFile(args[0])) {
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, error) {
expression := forceExpression
if expressionFile != "" {
expressionBytes, err := os.ReadFile(expressionFile)
if err != nil {
return "", nil, err
}
expression = string(expressionBytes)
}
args := processStdInArgs(pipingStdin, originalArgs)
yqlib.GetLogger().Debugf("processed args: %v", args)
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, nil
return printerWriter
}
+1 -1
View File
@@ -11,7 +11,7 @@ var (
GitDescribe string
// Version is main version number that is being run at the moment.
Version = "4.22.1"
Version = "4.16.2"
// 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
-109
View File
@@ -1,112 +1,3 @@
yq (4.16.2) focal; urgency=medium
* Fixed with semicolon space issue
* Updating with documentation
* Added STDIN example to the top
* minor readme cleanup
* Help text tweak
* Fixed docker timeout - simplify docker builds
* New release with docker build fixes
* Updating to go 1.17 to fix CVE #944
* Fix a typo in root.go
* Skip the tests if the nocheck Debian build option is specified
* Fixed select bug (#958)
* Sped up explode operator
* Slight performance improvement to context.ChildContext
* Speed up multiply
* Update README with recently added / changed options
* Make deepMatch report in linear time
* Removed leadingContentPreProcessing flag - header preprocessing is stable
* Revert "Removed leadingContentPreProcessing flag - header preprocessing is stable"
* Keep flag, it is needed in corner cases
* Updated Readme
* Man page
* Fixed expression parsing bug #970
* Bumping go-lang, docker versions
* Added test release flow
* Updated github action release to generate man page
* Bumping version
* Removing no longer needed github action
* Added decoder op
* Fixed newline handling when decoding/encoding
* Fixed newline handling in encoder/decoder
* Can specify indent in encode ops
* Added group_by operator
* Added flatten operator
* Fixed flatten error message
* Improving docs
* Split printer
* Refactored command logic
* Fix JSON encoding removing null #985
* Fixed acceptance tests
* gitbook
* Update document generation script
* Updating README
* Updating release instructions
* github action no longer uses data1.yml
* Create dependabot.yml
* Bump actions/create-release from 1.0.0 to 1.1.4
* Bump actions/setup-go from 1 to 2.1.4
* Bump github.com/goccy/go-yaml from 1.8.9 to 1.9.4
* Bump github.com/jinzhu/copier from 0.2.8 to 0.3.2
* Bump github.com/fatih/color from 1.10.0 to 1.13.0
* Bump github.com/spf13/cobra from 1.1.3 to 1.2.1
* Update dependabot.yml
* Update go.yml
* add build check to PRs
* Include secure as part of build process
* Fixing bad label in github action
* fixed printer test
* remove leading content indicator
* Fixed header preprocessing!
* lint : define golangci configuration file
* Update check.sh
* Load file acceptance test
* Minor improvement on handling front matter
* Improved load doc
* feature: detect MANPATh and install there
* Update install-man-page.sh
* simplify prod stage, move version label to action
* add labels, quote some values
* enable errorlint linter
* Added errorlint to devtools
* Added key operator
* Added more tests
* Fixing comments
* Attempt to fix golint problem
* Include version query for tools
* Clean up errored file?
* enable misspell linter
* updated readme
* update Golangci version to v1.43.0
* gci linter
* Better merge array by key example
* Added credit for merge by array example
* Better formatting of merge arrays example
* Better merge example
* Add accessor for the yq logger instance (#1013)
* Fixed collect op when working with multiple nodes
* Added map, map_values
* Add support for Podman as well as Docker (#1026)
* Bump github.com/jinzhu/copier from 0.3.2 to 0.3.4 (#1027)
* Added csv, tsv output formats
* Added encoder tests
* Cleanup test
* Fixed docker permission issue #1014
* Recording release notes for next release
* Assignment op no longer clobbers anchor (#1029)
* Added sort_by operator
* Improved error message
* Improved tips and tricks
* Report while filename failed to parse #1030
* Added script for extracting checksums
* Improved extract-checksum.sh
* Bump github.com/spf13/cobra from 1.2.1 to 1.3.0 (#1039)
* enable more linters (#1043)
* Bump golang compiler #1037
-- Roberto Mier Escandon <rmescandon@gmail.com> Tue, 21 Dec 2021 09:41:44 +0000
yq (4.13.0) focal; urgency=medium
* New `with` operator for making multiple changes to a given path
+1 -2
View File
@@ -3,8 +3,7 @@ Section: devel
Priority: optional
Maintainer: Roberto Mier Escandón <rmescandon@gmail.com>
Build-Depends: debhelper (>=10),
golang-1.17-go,
pandoc,
golang-1.15,
rsync
Standards-Version: 4.1.4
Homepage: https://github.com/mikefarah/yq.git
+4 -19
View File
@@ -1,6 +1,6 @@
#!/usr/bin/make -f
#
# Copyright (C) 2018-2021 Roberto Mier Escandón <rmescandon@gmail.com>
# Copyright (C) 2018 Roberto Mier Escandón <rmescandon@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
@@ -17,21 +17,20 @@
PROJECT := yq
OWNER := mikefarah
REPO := github.com
GOVERSION := 1.15
export DH_OPTIONS
export DH_GOPKG := ${REPO}/${OWNER}/${PROJECT}
export GOROOT := /usr/local/go
export GOROOT := /usr/lib/go-${GOVERSION}
export GOPATH := ${CURDIR}/_build
export GOBIN := ${GOPATH}/bin
export PATH := ${GOROOT}/bin:${GOBIN}:${PATH}
export GOCACHE := /tmp/gocache
export GOFLAGS := -mod=vendor
export GO111MODULE := on
SRCDIR := ${GOPATH}/src/${DH_GOPKG}
DESTDIR := ${CURDIR}/debian/${PROJECT}
BINDIR := /usr/bin
MANDIR := /usr/share/man/man1/
ASSETSDIR := /usr/share/${PROJECT}
%:
@@ -43,17 +42,7 @@ override_dh_auto_build:
# copy project to local srcdir to build from there
rsync -avz --progress --exclude=_build --exclude=debian --exclude=tmp. --exclude=go.mod --exclude=docs . $(SRCDIR)
# build go code
( \
cd ${SRCDIR} && \
go install -buildmode=pie ./... \
)
# build man page
( \
cd ${SRCDIR} && \
./scripts/generate-man-page-md.sh && \
./scripts/generate-man-page.sh \
)
(cd ${SRCDIR} && go install -buildmode=pie ./...)
override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
@@ -65,10 +54,6 @@ override_dh_auto_install:
cp -f ${SRCDIR}/LICENSE ${DESTDIR}/${ASSETSDIR}
chmod a+x ${DESTDIR}/${BINDIR}/yq
# man
mkdir -p "${DESTDIR}"/"${MANDIR}"
cp "${SRCDIR}"/yq.1 "${DESTDIR}"/"${MANDIR}" \
override_dh_auto_clean:
dh_clean
rm -rf ${CURDIR}/_build
-1
View File
@@ -1 +0,0 @@
bXkgc2VjcmV0IGNoaWxsaSByZWNpcGUgaXMuLi4u
+15 -1
View File
@@ -1 +1,15 @@
cat: purrs
strings:
- a: banana
- a: cat
- a: apple
numbers:
- a: 12
- a: 13
- a: 120
obj:
- a: {cat: "adog"}
- a: {cat: "doga"}
- a: apple
-6
View File
@@ -1,6 +0,0 @@
# comments on values appear
person.name = Mike
# comments on array values appear
person.pets.0 = cat
person.food.0 = pizza
+4 -14
View File
@@ -1,14 +1,4 @@
<!-- 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 -->
<?xml version="1.0" encoding="UTF-8"?>
<cat>3f</cat>
<dog>meow:as</dog>
<dog3>true</dog3>
-1
View File
@@ -1 +0,0 @@
this.is = a properties file
-1
View File
@@ -1 +0,0 @@
<this>is some xml</this>
+3 -5
View File
@@ -1,13 +1,11 @@
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.5
github.com/magiconair/properties v1.8.6
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
github.com/goccy/go-yaml v1.9.4
github.com/jinzhu/copier v0.3.4
github.com/magiconair/properties v1.8.5
github.com/spf13/cobra v1.3.0
github.com/timtadh/lexmachine v0.2.2
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
+5 -10
View File
@@ -50,8 +50,6 @@ 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=
@@ -125,8 +123,8 @@ github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTM
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-yaml v1.9.5 h1:Eh/+3uk9kLxG4koCX6lRMAPS1OaMSAi+FJcya0INdB0=
github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
github.com/goccy/go-yaml v1.9.4 h1:S0GCYjwHKVI6IHqio7QWNKNThUl6NLzFd/g8Z65Axw8=
github.com/goccy/go-yaml v1.9.4/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -237,8 +235,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.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jinzhu/copier v0.3.4 h1:mfU6jI9PtCeUjkjQ322dlff9ELjGDu975C2p/nrubVI=
github.com/jinzhu/copier v0.3.4/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=
@@ -259,9 +257,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -295,8 +292,6 @@ 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=
+8
View File
@@ -0,0 +1,8 @@
#!/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
+3 -2
View File
@@ -19,10 +19,11 @@ type Evaluator interface {
type allAtOnceEvaluator struct {
treeNavigator DataTreeNavigator
treeCreator ExpressionParser
}
func NewAllAtOnceEvaluator() Evaluator {
return &allAtOnceEvaluator{treeNavigator: NewDataTreeNavigator()}
return &allAtOnceEvaluator{treeNavigator: NewDataTreeNavigator(), treeCreator: NewExpressionParser()}
}
func (e *allAtOnceEvaluator) EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error) {
@@ -34,7 +35,7 @@ func (e *allAtOnceEvaluator) EvaluateNodes(expression string, nodes ...*yaml.Nod
}
func (e *allAtOnceEvaluator) EvaluateCandidateNodes(expression string, inputCandidates *list.List) (*list.List, error) {
node, err := ExpressionParser.ParseExpression(expression)
node, err := e.treeCreator.ParseExpression(expression)
if err != nil {
return nil, err
}
-1
View File
@@ -31,7 +31,6 @@ var evaluateNodesScenario = []expressionScenario{
}
func TestAllAtOnceEvaluateNodes(t *testing.T) {
InitExpressionParser()
var evaluator = NewAllAtOnceEvaluator()
for _, tt := range evaluateNodesScenario {
node := test.ParseData(tt.document)
+3 -20
View File
@@ -116,26 +116,15 @@ func (n *CandidateNode) Copy() (*CandidateNode, error) {
if err != nil {
return nil, err
}
clone.Node = deepClone(n.Node)
return clone, nil
}
// updates this candidate from the given candidate node
func (n *CandidateNode) UpdateFrom(other *CandidateNode, prefs assignPreferences) {
// if this is an empty map or empty array, use the style of other node.
if (n.Node.Kind != yaml.ScalarNode && len(n.Node.Content) == 0) ||
// if the tag has changed (e.g. from str to bool)
(guessTagFromCustomType(n.Node) != guessTagFromCustomType(other.Node)) {
n.Node.Style = other.Node.Style
}
n.Node.Content = deepCloneContent(other.Node.Content)
n.Node.Kind = other.Node.Kind
n.Node.Value = other.Node.Value
n.UpdateAttributesFrom(other, prefs)
n.Node.Content = other.Node.Content
n.Node.Value = other.Node.Value
}
func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode, prefs assignPreferences) {
@@ -147,12 +136,7 @@ func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode, prefs assignP
n.Node.Value = ""
}
n.Node.Kind = other.Node.Kind
// don't clobber custom tags...
if strings.HasPrefix(n.Node.Tag, "!!") || n.Node.Tag == "" {
n.Node.Tag = other.Node.Tag
}
n.Node.Tag = other.Node.Tag
n.Node.Alias = other.Node.Alias
if !prefs.DontOverWriteAnchor {
@@ -161,7 +145,6 @@ 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 {
n.Node.Style = other.Node.Style
}
+1 -14
View File
@@ -3,7 +3,6 @@ package yqlib
import (
"container/list"
"fmt"
"time"
"github.com/jinzhu/copier"
logging "gopkg.in/op/go-logging.v1"
@@ -13,7 +12,6 @@ type Context struct {
MatchingNodes *list.List
Variables map[string]*list.List
DontAutoCreate bool
datetimeLayout string
}
func (n *Context) SingleReadonlyChildContext(candidate *CandidateNode) Context {
@@ -30,17 +28,6 @@ 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
@@ -56,7 +43,7 @@ func (n *Context) SetVariable(name string, value *list.List) {
}
func (n *Context) ChildContext(results *list.List) Context {
clone := Context{DontAutoCreate: n.DontAutoCreate, datetimeLayout: n.datetimeLayout}
clone := Context{DontAutoCreate: n.DontAutoCreate}
clone.Variables = make(map[string]*list.List)
if len(n.Variables) > 0 {
err := copier.Copy(&clone.Variables, n.Variables)
+110
View File
@@ -0,0 +1,110 @@
package yqlib
import (
"bufio"
"bytes"
"fmt"
"strings"
"testing"
"github.com/mikefarah/yq/v4/test"
yaml "gopkg.in/yaml.v3"
)
func decodeXml(t *testing.T, xml string) *CandidateNode {
decoder := NewXmlDecoder("+", "+content")
decoder.Init(strings.NewReader(xml))
node := &yaml.Node{}
err := decoder.Decode(node)
if err != nil {
t.Error(err, "fail to decode", xml)
}
return &CandidateNode{Node: node}
}
type xmlScenario struct {
inputXml string
expected string
description string
subdescription string
skipDoc bool
}
var xmlScenarios = []xmlScenario{
{
description: "Parse xml: simple",
inputXml: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<cat>meow</cat>",
expected: "D0, P[], (doc)::cat: meow\n",
},
{
description: "Parse xml: array",
subdescription: "Consecutive nodes with identical xml names are assumed to be arrays.",
inputXml: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animal>1</animal>\n<animal>2</animal>",
expected: "D0, P[], (doc)::animal:\n - \"1\"\n - \"2\"\n",
},
{
description: "Parse xml: attributes",
subdescription: "Attributes are converted to fields, with the attribute prefix.",
inputXml: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<cat legs=\"4\">\n <legs>7</legs>\n</cat>",
expected: "D0, P[], (doc)::cat:\n +legs: \"4\"\n legs: \"7\"\n",
},
{
description: "Parse xml: attributes with content",
subdescription: "Content is added as a field, using the content name",
inputXml: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<cat legs=\"4\">meow</cat>",
expected: "D0, P[], (doc)::cat:\n +content: meow\n +legs: \"4\"\n",
},
}
func testXmlScenario(t *testing.T, s *xmlScenario) {
var actual = resultToString(t, decodeXml(t, s.inputXml))
test.AssertResult(t, s.expected, actual)
}
func documentXmlScenario(t *testing.T, w *bufio.Writer, i interface{}) {
s := i.(xmlScenario)
if s.skipDoc {
return
}
writeOrPanic(w, fmt.Sprintf("## %v\n", s.description))
if s.subdescription != "" {
writeOrPanic(w, s.subdescription)
writeOrPanic(w, "\n\n")
}
writeOrPanic(w, "Given a sample.xml file of:\n")
writeOrPanic(w, fmt.Sprintf("```xml\n%v\n```\n", s.inputXml))
writeOrPanic(w, "then\n")
writeOrPanic(w, "```bash\nyq e sample.xml\n```\n")
writeOrPanic(w, "will output\n")
var output bytes.Buffer
printer := NewPrinterWithSingleWriter(bufio.NewWriter(&output), YamlOutputFormat, true, false, 2, true)
node := decodeXml(t, s.inputXml)
err := printer.PrintResults(node.AsList())
if err != nil {
t.Error(err)
return
}
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", output.String()))
}
func TestXmlScenarios(t *testing.T) {
for _, tt := range xmlScenarios {
testXmlScenario(t, &tt)
}
genericScenarios := make([]interface{}, len(xmlScenarios))
for i, s := range xmlScenarios {
genericScenarios[i] = s
}
documentScenarios(t, "usage", "xml", genericScenarios, documentXmlScenario)
}
-35
View File
@@ -1,35 +0,0 @@
package yqlib
import (
"fmt"
"io"
yaml "gopkg.in/yaml.v3"
)
type InputFormat uint
const (
YamlInputFormat = 1 << iota
XMLInputFormat
PropertiesInputFormat
Base64InputFormat
)
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)
}
}
-44
View File
@@ -1,44 +0,0 @@
package yqlib
import (
"bytes"
"encoding/base64"
"io"
yaml "gopkg.in/yaml.v3"
)
type base64Decoder struct {
reader io.Reader
finished bool
encoding base64.Encoding
}
func NewBase64Decoder() Decoder {
return &base64Decoder{finished: false, encoding: *base64.StdEncoding}
}
func (dec *base64Decoder) Init(reader io.Reader) {
dec.reader = reader
dec.finished = false
}
func (dec *base64Decoder) Decode(rootYamlNode *yaml.Node) error {
if dec.finished {
return io.EOF
}
base64Reader := base64.NewDecoder(&dec.encoding, dec.reader)
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(base64Reader); err != nil {
return err
}
if buf.Len() == 0 {
dec.finished = true
return io.EOF
}
rootYamlNode.Kind = yaml.ScalarNode
rootYamlNode.Tag = "!!str"
rootYamlNode.Value = buf.String()
return nil
}
-122
View File
@@ -1,122 +0,0 @@
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
}
properties.DisableExpansion = true
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
}
-60
View File
@@ -1,60 +0,0 @@
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()
}
+37 -105
View File
@@ -2,26 +2,44 @@ 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
contentName string
contentPrefix string
finished bool
}
func NewXMLDecoder(attributePrefix string, contentName string) Decoder {
if contentName == "" {
contentName = "content"
func NewXmlDecoder(attributePrefix string, contentPrefix string) Decoder {
if contentPrefix == "" {
contentPrefix = "content"
}
return &xmlDecoder{attributePrefix: attributePrefix, contentName: contentName, finished: false}
return &xmlDecoder{attributePrefix: attributePrefix, contentPrefix: contentPrefix, finished: false}
}
func (dec *xmlDecoder) Init(reader io.Reader) {
@@ -42,41 +60,20 @@ 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) {
log.Debug("createMap: headC: %v, footC: %v", n.HeadComment, n.FootComment)
yamlNode := &yaml.Node{Kind: yaml.MappingNode}
yamlNode := &yaml.Node{Kind: yaml.MappingNode, HeadComment: n.Comment}
if len(n.Data) > 0 {
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))
label := dec.contentPrefix
yamlNode.Content = append(yamlNode.Content, createScalarNode(label, label), createScalarNode(n.Data, n.Data))
}
for i, keyValuePair := range n.Children {
for _, 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)
@@ -84,13 +81,6 @@ 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
@@ -107,14 +97,7 @@ func (dec *xmlDecoder) convertToYamlNode(n *xmlNode) (*yaml.Node, error) {
return dec.createMap(n)
}
scalar := createScalarNode(n.Data, n.Data)
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)
scalar.HeadComment = n.Comment
return scalar, nil
}
@@ -124,7 +107,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
@@ -133,9 +116,6 @@ 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}
@@ -144,17 +124,14 @@ func (dec *xmlDecoder) Decode(rootYamlNode *yaml.Node) error {
}
type xmlNode struct {
Children []*xmlChildrenKv
HeadComment string
FootComment string
LineComment string
Data string
Children []*xmlChildrenKv
Comment string
Data string
}
type xmlChildrenKv struct {
K string
V []*xmlNode
FootComment string
K string
V []*xmlNode
}
// AddChild appends a node to the list of children
@@ -181,13 +158,12 @@ 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
@@ -207,8 +183,6 @@ 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,
@@ -223,13 +197,7 @@ 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)
@@ -238,49 +206,13 @@ func (dec *xmlDecoder) decodeXML(root *xmlNode) error {
// Then change the current element to its parent
elem = elem.parent
case xml.Comment:
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})
}
elem.n.Comment = trimNonGraphic(string(xml.CharData(se)))
}
}
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.
//
+5
View File
@@ -6,6 +6,11 @@ import (
yaml "gopkg.in/yaml.v3"
)
type Decoder interface {
Init(reader io.Reader)
Decode(node *yaml.Node) error
}
type yamlDecoder struct {
decoder yaml.Decoder
}
-6
View File
@@ -1,6 +0,0 @@
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
+102 -158
View File
@@ -4,16 +4,31 @@ 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`.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## 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
```
## Concatenate arrays
Given a sample.yml file of:
@@ -27,7 +42,7 @@ b:
```
then
```bash
yq '.a + .b' sample.yml
yq eval '.a + .b' sample.yml
```
will output
```yaml
@@ -37,28 +52,6 @@ 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
@@ -68,7 +61,7 @@ a:
```
then
```bash
yq '.a + null' sample.yml
yq eval '.a + null' sample.yml
```
will output
```yaml
@@ -76,22 +69,6 @@ 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
@@ -100,7 +77,7 @@ a:
```
then
```bash
yq '.a + {"cat": "meow"}' sample.yml
yq eval '.a + {"cat": "meow"}' sample.yml
```
will output
```yaml
@@ -108,6 +85,76 @@ 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
@@ -122,7 +169,7 @@ a:
```
then
```bash
yq '.a[].b += ["mouse"]' sample.yml
yq eval '.a[].b += ["mouse"]' sample.yml
```
will output
```yaml
@@ -146,7 +193,7 @@ b: meow
```
then
```bash
yq '.a += .b' sample.yml
yq eval '.a = .a + .b' sample.yml
```
will output
```yaml
@@ -164,7 +211,7 @@ b: 4.9
```
then
```bash
yq '.a = .a + .b' sample.yml
yq eval '.a = .a + .b' sample.yml
```
will output
```yaml
@@ -182,7 +229,7 @@ b: 4
```
then
```bash
yq '.a = .a + .b' sample.yml
yq eval '.a = .a + .b' sample.yml
```
will output
```yaml
@@ -198,7 +245,7 @@ b: 5
```
then
```bash
yq '.[] += 1' sample.yml
yq eval '.[] += 1' sample.yml
```
will output
```yaml
@@ -206,118 +253,15 @@ 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 --null-input 'null + "cat"'
yq eval --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,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## LHS is defined
Given a sample.yml file of:
```yaml
@@ -15,7 +9,7 @@ a: bridge
```
then
```bash
yq '.a // "hello"' sample.yml
yq eval '.a // "hello"' sample.yml
```
will output
```yaml
@@ -29,7 +23,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.a // "hello"' sample.yml
yq eval '.a // "hello"' sample.yml
```
will output
```yaml
@@ -43,7 +37,7 @@ a: ~
```
then
```bash
yq '.a // "hello"' sample.yml
yq eval '.a // "hello"' sample.yml
```
will output
```yaml
@@ -57,7 +51,7 @@ a: false
```
then
```bash
yq '.a // "hello"' sample.yml
yq eval '.a // "hello"' sample.yml
```
will output
```yaml
@@ -72,7 +66,7 @@ b: cat
```
then
```bash
yq '.a // .b' sample.yml
yq eval '.a // .b' sample.yml
```
will output
```yaml
@@ -5,12 +5,6 @@ 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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Merge one map
see https://yaml.org/type/merge.html
@@ -31,7 +25,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[4] | explode(.)' sample.yml
yq eval '.[4] | explode(.)' sample.yml
```
will output
```yaml
@@ -61,7 +55,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[4] | explode(.)' sample.yml
yq eval '.[4] | explode(.)' sample.yml
```
will output
```yaml
@@ -93,7 +87,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[4] | explode(.)' sample.yml
yq eval '.[4] | explode(.)' sample.yml
```
will output
```yaml
@@ -109,7 +103,7 @@ a: &billyBob cat
```
then
```bash
yq '.a | anchor' sample.yml
yq eval '.a | anchor' sample.yml
```
will output
```yaml
@@ -123,7 +117,7 @@ a: cat
```
then
```bash
yq '.a anchor = "foobar"' sample.yml
yq eval '.a anchor = "foobar"' sample.yml
```
will output
```yaml
@@ -138,7 +132,7 @@ a:
```
then
```bash
yq '.a anchor |= .b' sample.yml
yq eval '.a anchor |= .b' sample.yml
```
will output
```yaml
@@ -154,7 +148,7 @@ a: *billyBob
```
then
```bash
yq '.a | alias' sample.yml
yq eval '.a | alias' sample.yml
```
will output
```yaml
@@ -169,7 +163,7 @@ a: cat
```
then
```bash
yq '.a alias = "meow"' sample.yml
yq eval '.a alias = "meow"' sample.yml
```
will output
```yaml
@@ -185,7 +179,7 @@ a: cat
```
then
```bash
yq '.a alias = ""' sample.yml
yq eval '.a alias = ""' sample.yml
```
will output
```yaml
@@ -202,7 +196,7 @@ a:
```
then
```bash
yq '.a alias |= .f' sample.yml
yq eval '.a alias |= .f' sample.yml
```
will output
```yaml
@@ -219,7 +213,7 @@ f:
```
then
```bash
yq 'explode(.f)' sample.yml
yq eval 'explode(.f)' sample.yml
```
will output
```yaml
@@ -235,7 +229,7 @@ a: mike
```
then
```bash
yq 'explode(.a)' sample.yml
yq eval 'explode(.a)' sample.yml
```
will output
```yaml
@@ -251,7 +245,7 @@ f:
```
then
```bash
yq 'explode(.f)' sample.yml
yq eval 'explode(.f)' sample.yml
```
will output
```yaml
@@ -284,7 +278,7 @@ foobar:
```
then
```bash
yq 'explode(.)' sample.yml
yq eval 'explode(.)' sample.yml
```
will output
```yaml
@@ -323,7 +317,7 @@ thingTwo:
```
then
```bash
yq '.thingOne |= explode(.) * {"value": false}' sample.yml
yq eval '.thingOne |= explode(.) * {"value": false}' sample.yml
```
will output
```yaml
+12 -18
View File
@@ -7,16 +7,10 @@ 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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Create yaml file
Running
```bash
yq --null-input '.a.b = "cat" | .x = "frog"'
yq eval --null-input '.a.b = "cat" | .x = "frog"'
```
will output
```yaml
@@ -34,7 +28,7 @@ a:
```
then
```bash
yq '.a |= .b' sample.yml
yq eval '.a |= .b' sample.yml
```
will output
```yaml
@@ -51,7 +45,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] |= . * 2' sample.yml
yq eval '.[] |= . * 2' sample.yml
```
will output
```yaml
@@ -90,7 +84,7 @@ b: sibling
```
then
```bash
yq '.a = .b' sample.yml
yq eval '.a = .b' sample.yml
```
will output
```yaml
@@ -107,7 +101,7 @@ c: fieldC
```
then
```bash
yq '(.a, .c) = "potatoe"' sample.yml
yq eval '(.a, .c) = "potatoe"' sample.yml
```
will output
```yaml
@@ -124,7 +118,7 @@ a:
```
then
```bash
yq '.a.b = "frog"' sample.yml
yq eval '.a.b = "frog"' sample.yml
```
will output
```yaml
@@ -142,7 +136,7 @@ a:
```
then
```bash
yq '.a.b |= "frog"' sample.yml
yq eval '.a.b |= "frog"' sample.yml
```
will output
```yaml
@@ -161,7 +155,7 @@ a:
```
then
```bash
yq '(.a[] | select(. == "apple")) = "frog"' sample.yml
yq eval '(.a[] | select(. == "apple")) = "frog"' sample.yml
```
will output
```yaml
@@ -179,7 +173,7 @@ Given a sample.yml file of:
```
then
```bash
yq '(.[] | select(. == "*andy")) = "bogs"' sample.yml
yq eval '(.[] | select(. == "*andy")) = "bogs"' sample.yml
```
will output
```yaml
@@ -195,7 +189,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.a.b |= "bogs"' sample.yml
yq eval '.a.b |= "bogs"' sample.yml
```
will output
```yaml
@@ -211,7 +205,7 @@ a: &cool cat
```
then
```bash
yq '.a = "dog"' sample.yml
yq eval '.a = "dog"' sample.yml
```
will output
```yaml
@@ -225,7 +219,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.a.b.[0] |= "bogs"' sample.yml
yq eval '.a.b.[0] |= "bogs"' sample.yml
```
will output
```yaml
+16 -22
View File
@@ -10,16 +10,10 @@ 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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## `or` example
Running
```bash
yq --null-input 'true or false'
yq eval --null-input 'true or false'
```
will output
```yaml
@@ -29,7 +23,7 @@ true
## `and` example
Running
```bash
yq --null-input 'true and false'
yq eval --null-input 'true and false'
```
will output
```yaml
@@ -48,7 +42,7 @@ Given a sample.yml file of:
```
then
```bash
yq '[.[] | select(.a == "cat" or .b == "dog")]' sample.yml
yq eval '[.[] | select(.a == "cat" or .b == "dog")]' sample.yml
```
will output
```yaml
@@ -66,7 +60,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'any' sample.yml
yq eval 'any' sample.yml
```
will output
```yaml
@@ -80,7 +74,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'any' sample.yml
yq eval 'any' sample.yml
```
will output
```yaml
@@ -99,7 +93,7 @@ b:
```
then
```bash
yq '.[] |= any_c(. == "awesome")' sample.yml
yq eval '.[] |= any_c(. == "awesome")' sample.yml
```
will output
```yaml
@@ -115,7 +109,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'all' sample.yml
yq eval 'all' sample.yml
```
will output
```yaml
@@ -129,7 +123,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'all' sample.yml
yq eval 'all' sample.yml
```
will output
```yaml
@@ -148,7 +142,7 @@ b:
```
then
```bash
yq '.[] |= all_c(tag == "!!str")' sample.yml
yq eval '.[] |= all_c(tag == "!!str")' sample.yml
```
will output
```yaml
@@ -159,7 +153,7 @@ b: false
## Not true is false
Running
```bash
yq --null-input 'true | not'
yq eval --null-input 'true | not'
```
will output
```yaml
@@ -169,7 +163,7 @@ false
## Not false is true
Running
```bash
yq --null-input 'false | not'
yq eval --null-input 'false | not'
```
will output
```yaml
@@ -179,7 +173,7 @@ true
## String values considered to be true
Running
```bash
yq --null-input '"cat" | not'
yq eval --null-input '"cat" | not'
```
will output
```yaml
@@ -189,7 +183,7 @@ false
## Empty string value considered to be true
Running
```bash
yq --null-input '"" | not'
yq eval --null-input '"" | not'
```
will output
```yaml
@@ -199,7 +193,7 @@ false
## Numbers are considered to be true
Running
```bash
yq --null-input '1 | not'
yq eval --null-input '1 | not'
```
will output
```yaml
@@ -209,7 +203,7 @@ false
## Zero is considered to be true
Running
```bash
yq --null-input '0 | not'
yq eval --null-input '0 | not'
```
will output
```yaml
@@ -219,7 +213,7 @@ false
## Null is considered to be false
Running
```bash
yq --null-input '~ | not'
yq eval --null-input '~ | not'
```
will output
```yaml
@@ -3,16 +3,10 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Collect empty
Running
```bash
yq --null-input '[]'
yq eval --null-input '[]'
```
will output
```yaml
@@ -22,7 +16,7 @@ will output
## Collect single
Running
```bash
yq --null-input '["cat"]'
yq eval --null-input '["cat"]'
```
will output
```yaml
@@ -37,7 +31,7 @@ b: dog
```
then
```bash
yq '[.a, .b]' sample.yml
yq eval '[.a, .b]' sample.yml
```
will output
```yaml
-66
View File
@@ -1,66 +0,0 @@
# Column
Returns the column of the matching node. Starts from 1, 0 indicates there was no column data.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Returns column of _value_ node
Given a sample.yml file of:
```yaml
a: cat
b: bob
```
then
```bash
yq '.b | column' sample.yml
```
will output
```yaml
4
```
## Returns column of _key_ node
Pipe through the key operator to get the column of the key
Given a sample.yml file of:
```yaml
a: cat
b: bob
```
then
```bash
yq '.b | key | column' sample.yml
```
will output
```yaml
1
```
## First column is 1
Given a sample.yml file of:
```yaml
a: cat
```
then
```bash
yq '.a | key | column' sample.yml
```
will output
```yaml
1
```
## No column data is 0
Running
```bash
yq --null-input '{"a": "new entry"} | column'
```
will output
```yaml
0
```
+10 -16
View File
@@ -10,12 +10,6 @@ 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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Set line comment
Given a sample.yml file of:
```yaml
@@ -23,7 +17,7 @@ a: cat
```
then
```bash
yq '.a line_comment="single"' sample.yml
yq eval '.a lineComment="single"' sample.yml
```
will output
```yaml
@@ -38,7 +32,7 @@ b: dog
```
then
```bash
yq '.. line_comment |= .' sample.yml
yq eval '.. lineComment |= .' sample.yml
```
will output
```yaml
@@ -53,7 +47,7 @@ a: cat
```
then
```bash
yq '. head_comment="single"' sample.yml
yq eval '. headComment="single"' sample.yml
```
will output
```yaml
@@ -69,7 +63,7 @@ a: cat
```
then
```bash
yq '. foot_comment=.a' sample.yml
yq eval '. footComment=.a' sample.yml
```
will output
```yaml
@@ -86,7 +80,7 @@ b: dog # leave this
```
then
```bash
yq '.a line_comment=""' sample.yml
yq eval '.a lineComment=""' sample.yml
```
will output
```yaml
@@ -105,7 +99,7 @@ b: # key comment
```
then
```bash
yq '... comments=""' sample.yml
yq eval '... comments=""' sample.yml
```
will output
```yaml
@@ -120,7 +114,7 @@ a: cat # meow
```
then
```bash
yq '.a | line_comment' sample.yml
yq eval '.a | lineComment' sample.yml
```
will output
```yaml
@@ -138,7 +132,7 @@ a: cat # meow
```
then
```bash
yq '. | head_comment' sample.yml
yq eval '. | headComment' sample.yml
```
will output
```yaml
@@ -157,7 +151,7 @@ a: cat # meow
```
then
```bash
yq 'head_comment' sample.yml
yq eval 'headComment' sample.yml
```
will output
```yaml
@@ -177,7 +171,7 @@ a: cat # meow
```
then
```bash
yq '. | foot_comment' sample.yml
yq eval '. | footComment' sample.yml
```
will output
```yaml
+5 -11
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Array contains array
Array is equal or subset of
@@ -19,7 +13,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'contains(["baz", "bar"])' sample.yml
yq eval 'contains(["baz", "bar"])' sample.yml
```
will output
```yaml
@@ -38,7 +32,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'contains({"bar": [{"barp": 12}]})' sample.yml
yq eval 'contains({"bar": [{"barp": 12}]})' sample.yml
```
will output
```yaml
@@ -57,7 +51,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'contains({"foo": 12, "bar": [{"barp": 15}]})' sample.yml
yq eval 'contains({"foo": 12, "bar": [{"barp": 15}]})' sample.yml
```
will output
```yaml
@@ -71,7 +65,7 @@ foobar
```
then
```bash
yq 'contains("bar")' sample.yml
yq eval 'contains("bar")' sample.yml
```
will output
```yaml
@@ -85,7 +79,7 @@ meow
```
then
```bash
yq 'contains("meow")' sample.yml
yq eval 'contains("meow")' sample.yml
```
will output
```yaml
@@ -2,16 +2,10 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Collect empty object
Running
```bash
yq --null-input '{}'
yq eval --null-input '{}'
```
will output
```yaml
@@ -25,7 +19,7 @@ name: Mike
```
then
```bash
yq '{"wrap": .}' sample.yml
yq eval '{"wrap": .}' sample.yml
```
will output
```yaml
@@ -43,7 +37,7 @@ pets:
```
then
```bash
yq '{.name: .pets.[]}' sample.yml
yq eval '{.name: .pets.[]}' sample.yml
```
will output
```yaml
@@ -66,7 +60,7 @@ pets:
```
then
```bash
yq '{.name: .pets.[]}' sample.yml
yq eval '{.name: .pets.[]}' sample.yml
```
will output
```yaml
@@ -79,7 +73,7 @@ Rosey: sheep
## Creating yaml from scratch
Running
```bash
yq --null-input '{"wrap": "frog"}'
yq eval --null-input '{"wrap": "frog"}'
```
will output
```yaml
-203
View File
@@ -1,203 +0,0 @@
# 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.&#x20;
`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
```
+7 -13
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Delete entry in map
Given a sample.yml file of:
```yaml
@@ -16,7 +10,7 @@ b: dog
```
then
```bash
yq 'del(.b)' sample.yml
yq eval 'del(.b)' sample.yml
```
will output
```yaml
@@ -32,7 +26,7 @@ a:
```
then
```bash
yq 'del(.a.a1)' sample.yml
yq eval 'del(.a.a1)' sample.yml
```
will output
```yaml
@@ -49,7 +43,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'del(.[1])' sample.yml
yq eval 'del(.[1])' sample.yml
```
will output
```yaml
@@ -65,7 +59,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'del(.[0].a)' sample.yml
yq eval 'del(.[0].a)' sample.yml
```
will output
```yaml
@@ -80,7 +74,7 @@ b: dog
```
then
```bash
yq 'del(.c)' sample.yml
yq eval 'del(.c)' sample.yml
```
will output
```yaml
@@ -97,7 +91,7 @@ c: bat
```
then
```bash
yq 'del( .[] | select(. == "*at") )' sample.yml
yq eval 'del( .[] | select(. == "*at") )' sample.yml
```
will output
```yaml
@@ -115,7 +109,7 @@ a:
```
then
```bash
yq 'del(.. | select(has("name")).name)' sample.yml
yq eval 'del(.. | select(has("name")).name)' sample.yml
```
will output
```yaml
+5 -11
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Retrieve a document index
Given a sample.yml file of:
```yaml
@@ -17,7 +11,7 @@ a: frog
```
then
```bash
yq '.a | document_index' sample.yml
yq eval '.a | documentIndex' sample.yml
```
will output
```yaml
@@ -35,7 +29,7 @@ a: frog
```
then
```bash
yq '.a | di' sample.yml
yq eval '.a | di' sample.yml
```
will output
```yaml
@@ -53,7 +47,7 @@ a: frog
```
then
```bash
yq 'select(document_index == 1)' sample.yml
yq eval 'select(documentIndex == 1)' sample.yml
```
will output
```yaml
@@ -69,7 +63,7 @@ a: frog
```
then
```bash
yq 'select(di == 1)' sample.yml
yq eval 'select(di == 1)' sample.yml
```
will output
```yaml
@@ -85,7 +79,7 @@ a: frog
```
then
```bash
yq '.a | ({"match": ., "doc": document_index})' sample.yml
yq eval '.a | ({"match": ., "doc": documentIndex})' sample.yml
```
will output
```yaml
+14 -147
View File
@@ -14,22 +14,10 @@ These operators are useful to process yaml documents that have stringified embed
| Properties | | to_props/@props |
| CSV | | to_csv/@csv |
| TSV | | to_tsv/@tsv |
| XML | from_xml | to_xml(i)/@xml |
| Base64 | @base64d | @base64 |
CSV and TSV format both accept either a single array or scalars (representing a single row), or an array of array of scalars (representing multiple rows).
XML uses the `--xml-attribute-prefix` and `xml-content-name` flags to identify attributes and content fields.
Base64 assumes [rfc4648](https://rfc-editor.org/rfc/rfc4648.html) encoding. Encoding and decoding both assume that the content is a string.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Encode value as json string
Given a sample.yml file of:
@@ -39,7 +27,7 @@ a:
```
then
```bash
yq '.b = (.a | to_json)' sample.yml
yq eval '.b = (.a | to_json)' sample.yml
```
will output
```yaml
@@ -61,7 +49,7 @@ a:
```
then
```bash
yq '.b = (.a | to_json(0))' sample.yml
yq eval '.b = (.a | to_json(0))' sample.yml
```
will output
```yaml
@@ -80,7 +68,7 @@ a:
```
then
```bash
yq '.b = (.a | @json)' sample.yml
yq eval '.b = (.a | @json)' sample.yml
```
will output
```yaml
@@ -98,7 +86,7 @@ a: '{"cool":"thing"}'
```
then
```bash
yq '.a | from_json | ... style=""' sample.yml
yq eval '.a | from_json | ... style=""' sample.yml
```
will output
```yaml
@@ -113,7 +101,7 @@ a:
```
then
```bash
yq '.b = (.a | @props)' sample.yml
yq eval '.b = (.a | @props)' sample.yml
```
will output
```yaml
@@ -134,7 +122,7 @@ a:
```
then
```bash
yq '.b = (.a | to_yaml)' sample.yml
yq eval '.b = (.a | to_yaml)' sample.yml
```
will output
```yaml
@@ -157,7 +145,7 @@ a:
```
then
```bash
yq '.b = (.a | to_yaml(8))' sample.yml
yq eval '.b = (.a | to_yaml(8))' sample.yml
```
will output
```yaml
@@ -176,7 +164,7 @@ a: 'foo: bar'
```
then
```bash
yq '.b = (.a | from_yaml)' sample.yml
yq eval '.b = (.a | from_yaml)' sample.yml
```
will output
```yaml
@@ -195,7 +183,7 @@ a: |
```
then
```bash
yq '.a |= (from_yaml | .foo = "cat" | to_yaml)' sample.yml
yq eval '.a |= (from_yaml | .foo = "cat" | to_yaml)' sample.yml
```
will output
```yaml
@@ -211,7 +199,7 @@ a: 'foo: bar'
```
then
```bash
yq '.a |= (from_yaml | .foo = "cat" | to_yaml)' sample.yml
yq eval '.a |= (from_yaml | .foo = "cat" | to_yaml)' sample.yml
```
will output
```yaml
@@ -230,7 +218,7 @@ Given a sample.yml file of:
```
then
```bash
yq '@csv' sample.yml
yq eval '@csv' sample.yml
```
will output
```yaml
@@ -251,7 +239,7 @@ Given a sample.yml file of:
```
then
```bash
yq '@csv' sample.yml
yq eval '@csv' sample.yml
```
will output
```yaml
@@ -275,7 +263,7 @@ Given a sample.yml file of:
```
then
```bash
yq '@tsv' sample.yml
yq eval '@tsv' sample.yml
```
will output
```yaml
@@ -283,64 +271,6 @@ cat thing1,thing2 true 3.40
dog thing3 false 12
```
## Encode value as xml string
Given a sample.yml file of:
```yaml
a:
cool:
foo: bar
+id: hi
```
then
```bash
yq '.a | to_xml' sample.yml
```
will output
```yaml
<cool id="hi">
<foo>bar</foo>
</cool>
```
## Encode value as xml string on a single line
Given a sample.yml file of:
```yaml
a:
cool:
foo: bar
+id: hi
```
then
```bash
yq '.a | @xml' sample.yml
```
will output
```yaml
<cool id="hi"><foo>bar</foo></cool>
```
## Encode value as xml string with custom indentation
Given a sample.yml file of:
```yaml
a:
cool:
foo: bar
+id: hi
```
then
```bash
yq '{"cat": .a | to_xml(1)}' sample.yml
```
will output
```yaml
cat: |
<cool id="hi">
<foo>bar</foo>
</cool>
```
## Decode a xml encoded string
Given a sample.yml file of:
```yaml
@@ -348,7 +278,7 @@ a: <foo>bar</foo>
```
then
```bash
yq '.b = (.a | from_xml)' sample.yml
yq eval '.b = (.a | from_xml)' sample.yml
```
will output
```yaml
@@ -357,66 +287,3 @@ b:
foo: bar
```
## Encode a string to base64
Given a sample.yml file of:
```yaml
coolData: a special string
```
then
```bash
yq '.coolData | @base64' sample.yml
```
will output
```yaml
YSBzcGVjaWFsIHN0cmluZw==
```
## Encode a yaml document to base64
Pipe through @yaml first to convert to a string, then use @base64 to encode it.
Given a sample.yml file of:
```yaml
a: apple
```
then
```bash
yq '@yaml | @base64' sample.yml
```
will output
```yaml
YTogYXBwbGUK
```
## Decode a base64 encoded string
Decoded data is assumed to be a string.
Given a sample.yml file of:
```yaml
coolData: V29ya3Mgd2l0aCBVVEYtMTYg8J+Yig==
```
then
```bash
yq '.coolData | @base64d' sample.yml
```
will output
```yaml
Works with UTF-16 😊
```
## Decode a base64 encoded yaml document
Pipe through `from_yaml` to parse the decoded base64 string as a yaml document.
Given a sample.yml file of:
```yaml
coolData: YTogYXBwbGUK
```
then
```bash
yq '.coolData |= (@base64d | from_yaml)' sample.yml
```
will output
```yaml
coolData:
a: apple
```
+7 -13
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## to_entries Map
Given a sample.yml file of:
```yaml
@@ -16,7 +10,7 @@ b: 2
```
then
```bash
yq 'to_entries' sample.yml
yq eval 'to_entries' sample.yml
```
will output
```yaml
@@ -34,7 +28,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'to_entries' sample.yml
yq eval 'to_entries' sample.yml
```
will output
```yaml
@@ -51,7 +45,7 @@ null
```
then
```bash
yq 'to_entries' sample.yml
yq eval 'to_entries' sample.yml
```
will output
```yaml
@@ -65,7 +59,7 @@ b: 2
```
then
```bash
yq 'to_entries | from_entries' sample.yml
yq eval 'to_entries | from_entries' sample.yml
```
will output
```yaml
@@ -83,7 +77,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'to_entries | from_entries' sample.yml
yq eval 'to_entries | from_entries' sample.yml
```
will output
```yaml
@@ -99,7 +93,7 @@ b: 2
```
then
```bash
yq 'with_entries(.key |= "KEY_" + .)' sample.yml
yq eval 'with_entries(.key |= "KEY_" + .)' sample.yml
```
will output
```yaml
@@ -117,7 +111,7 @@ c:
```
then
```bash
yq 'with_entries(select(.value | has("b")))' sample.yml
yq eval 'with_entries(select(.value | has("b")))' sample.yml
```
will output
```yaml
@@ -1,32 +1,11 @@
# Env Variable Operators
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
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.
## Read string environment variable
Running
```bash
myenv="cat meow" yq --null-input '.a = env(myenv)'
myenv="cat meow" yq eval --null-input '.a = env(myenv)'
```
will output
```yaml
@@ -36,7 +15,7 @@ a: cat meow
## Read boolean environment variable
Running
```bash
myenv="true" yq --null-input '.a = env(myenv)'
myenv="true" yq eval --null-input '.a = env(myenv)'
```
will output
```yaml
@@ -46,7 +25,7 @@ a: true
## Read numeric environment variable
Running
```bash
myenv="12" yq --null-input '.a = env(myenv)'
myenv="12" yq eval --null-input '.a = env(myenv)'
```
will output
```yaml
@@ -56,7 +35,7 @@ a: 12
## Read yaml environment variable
Running
```bash
myenv="{b: fish}" yq --null-input '.a = env(myenv)'
myenv="{b: fish}" yq eval --null-input '.a = env(myenv)'
```
will output
```yaml
@@ -66,7 +45,7 @@ a: {b: fish}
## Read boolean environment variable as a string
Running
```bash
myenv="true" yq --null-input '.a = strenv(myenv)'
myenv="true" yq eval --null-input '.a = strenv(myenv)'
```
will output
```yaml
@@ -76,35 +55,13 @@ a: "true"
## Read numeric environment variable as a string
Running
```bash
myenv="12" yq --null-input '.a = strenv(myenv)'
myenv="12" yq eval --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
@@ -113,54 +70,10 @@ dog: woof
```
then
```bash
myenv="cat" yq '.[env(myenv)]' sample.yml
myenv="cat" yq eval '.[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
```
+7 -13
View File
@@ -12,12 +12,6 @@ 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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Match string
Given a sample.yml file of:
```yaml
@@ -27,7 +21,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | (. == "*at")' sample.yml
yq eval '.[] | (. == "*at")' sample.yml
```
will output
```yaml
@@ -45,7 +39,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | (. != "*at")' sample.yml
yq eval '.[] | (. != "*at")' sample.yml
```
will output
```yaml
@@ -63,7 +57,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | (. == 4)' sample.yml
yq eval '.[] | (. == 4)' sample.yml
```
will output
```yaml
@@ -81,7 +75,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | (. != 4)' sample.yml
yq eval '.[] | (. != 4)' sample.yml
```
will output
```yaml
@@ -93,7 +87,7 @@ true
## Match nulls
Running
```bash
yq --null-input 'null == ~'
yq eval --null-input 'null == ~'
```
will output
```yaml
@@ -107,7 +101,7 @@ a: frog
```
then
```bash
yq 'select(.b != "thing")' sample.yml
yq eval 'select(.b != "thing")' sample.yml
```
will output
```yaml
@@ -121,7 +115,7 @@ a: frog
```
then
```bash
yq 'select(.b == .c)' sample.yml
yq eval 'select(.b == .c)' sample.yml
```
will output
```yaml
-54
View File
@@ -1,54 +0,0 @@
# 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.&#x20;
`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
```
+4 -10
View File
@@ -10,12 +10,6 @@ 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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Get filename
Given a sample.yml file of:
```yaml
@@ -23,7 +17,7 @@ a: cat
```
then
```bash
yq 'filename' sample.yml
yq eval 'filename' sample.yml
```
will output
```yaml
@@ -37,7 +31,7 @@ a: cat
```
then
```bash
yq 'file_index' sample.yml
yq eval 'fileIndex' sample.yml
```
will output
```yaml
@@ -55,7 +49,7 @@ a: cat
```
then
```bash
yq eval-all 'file_index' sample.yml another.yml
yq eval-all 'fileIndex' sample.yml another.yml
```
will output
```yaml
@@ -71,7 +65,7 @@ a: cat
```
then
```bash
yq 'fi' sample.yml
yq eval 'fi' sample.yml
```
will output
```yaml
+4 -10
View File
@@ -1,12 +1,6 @@
# Flatten
This recursively flattens arrays.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Flatten
Recursively flattens all arrays
@@ -18,7 +12,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'flatten' sample.yml
yq eval 'flatten' sample.yml
```
will output
```yaml
@@ -36,7 +30,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'flatten(1)' sample.yml
yq eval 'flatten(1)' sample.yml
```
will output
```yaml
@@ -52,7 +46,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'flatten' sample.yml
yq eval 'flatten' sample.yml
```
will output
```yaml
@@ -67,7 +61,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'flatten' sample.yml
yq eval 'flatten' sample.yml
```
will output
```yaml
+2 -8
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Group by field
Given a sample.yml file of:
```yaml
@@ -20,7 +14,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'group_by(.foo)' sample.yml
yq eval 'group_by(.foo)' sample.yml
```
will output
```yaml
@@ -46,7 +40,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'group_by(.foo)' sample.yml
yq eval 'group_by(.foo)' sample.yml
```
will output
```yaml
+3 -9
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Has map key
Given a sample.yml file of:
```yaml
@@ -18,7 +12,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | has("a")' sample.yml
yq eval '.[] | has("a")' sample.yml
```
will output
```yaml
@@ -42,7 +36,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | select(.a.b | has("c"))' sample.yml
yq eval '.[] | select(.a.b | has("c"))' sample.yml
```
will output
```yaml
@@ -63,7 +57,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | has(1)' sample.yml
yq eval '.[] | has(1)' sample.yml
```
will output
```yaml
+6 -7
View File
@@ -5,7 +5,7 @@
yq [eval/eval-all] [expression] files..
eval/e - (default) Apply the expression to each document in each yaml file in sequence
eval/e - 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,33 +18,32 @@ This documentation is also available at https://mikefarah.gitbook.io/yq/
## Read a value:
```bash
yq '.a.b[0].c' file.yaml
yq e '.a.b[0].c' file.yaml
```
## Pipe from STDIN:
```bash
cat file.yaml | yq '.a.b[0].c'
cat file.yaml | yq e '.a.b[0].c' -
```
## Update a yaml file, inplace
```bash
yq -i '.a.b[0].c = "cool"' file.yaml
yq e -i '.a.b[0].c = "cool"' file.yaml
```
## Update using environment variables
```bash
NAME=mike yq -i '.a.b[0].c = strenv(NAME)' file.yaml
NAME=mike yq e -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 -i '
yq e -i '
.a.b[0].c = "cool" |
.x.y.z = "foobar" |
.person.name = strenv(NAME)
+1 -3
View File
@@ -4,7 +4,5 @@ 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`.
@@ -1,3 +0,0 @@
# Column
Returns the column of the matching node. Starts from 1, 0 indicates there was no column data.
@@ -1,26 +0,0 @@
# 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.
@@ -14,13 +14,8 @@ These operators are useful to process yaml documents that have stringified embed
| Properties | | to_props/@props |
| CSV | | to_csv/@csv |
| TSV | | to_tsv/@tsv |
| XML | from_xml | to_xml(i)/@xml |
| Base64 | @base64d | @base64 |
| XML | from_xml | |
CSV and TSV format both accept either a single array or scalars (representing a single row), or an array of array of scalars (representing multiple rows).
XML uses the `--xml-attribute-prefix` and `xml-content-name` flags to identify attributes and content fields.
Base64 assumes [rfc4648](https://rfc-editor.org/rfc/rfc4648.html) encoding. Encoding and decoding both assume that the content is a string.
@@ -1,18 +1,3 @@
# Env Variable Operators
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
```
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.
-7
View File
@@ -1,7 +0,0 @@
# 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.
-3
View File
@@ -1,3 +0,0 @@
# Line
Returns the line of the matching node. Starts from 1, 0 indicates there was no line data.
+3 -35
View File
@@ -1,46 +1,14 @@
# Load
The load operators allows you to load in content from another file.
The `load`/`strload` operator allows you to load in content from another file referenced in your yaml document.
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.
You can load files of the following supported types:
Use `strload` to load text based content as a string block, and `load` to interpret the file as yaml.
|Format | Load Operator |
| --- | --- |
| Yaml | load |
| XML | load_xml |
| Properties | load_props |
| Plain String | load_str |
| Base64 | load_base64 |
## Samples files for tests:
### yaml
`../../examples/thing.yml`:
Lets say there is a file `../../examples/thing.yml`:
```yaml
a: apple is included
b: cool
```
### xml
`small.xml`:
```xml
<this>is some xml</this>
```
### properties
`small.properties`:
```properties
this.is = a properties file
```
### base64
`base64.txt`:
```
bXkgc2VjcmV0IGNoaWxsaSByZWNpcGUgaXMuLi4u
```
@@ -10,10 +10,9 @@ 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
- `+` append arrays
- `d` deeply merge arrays
- `?` only merge _existing_ fields
- `n` only merge _new_ fields
- `+` to append arrays
- `?` to only merge existing fields
- `d` to deeply merge arrays
### Merging files
Note the use of `eval-all` to ensure all documents are loaded into memory.
-5
View File
@@ -1,5 +0,0 @@
# Pick
Filter a map by the specified list of keys. Map is returned with the key in the order of the pick list.
Similarly, filter an array by the specified list of indices.
@@ -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 '.. style= "flow"' file.yaml
yq eval '.. 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 '... style= "flow"' file.yaml
yq eval '... style= "flow"' file.yaml
```
@@ -1,3 +0,0 @@
# Reverse
Reverses the order of the items in an array
+2 -4
View File
@@ -5,9 +5,7 @@ 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 -i -P 'sort_keys(..)' file1.yml
yq -i -P 'sort_keys(..)' file2.yml
yq eval -i -P 'sort_keys(..)' file1.yml
yq eval -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.
-3
View File
@@ -2,7 +2,4 @@
Sorts an array. Use `sort` to sort an array as is, or `sort_by(exp)` to sort by a particular expression (e.g. subfield).
To sort by descending order, pipe the results through the `reverse` operator after sorting.
Note that at this stage, `yq` only sorts scalar fields.
@@ -17,13 +17,13 @@ a: |
Using `$( exp )` wont work, as it will trim the trailing new line.
```
m=$(echo "cat\n") yq -n '.a = strenv(m)'
m=$(echo "cat\n") yq e -n '.a = strenv(m)'
a: cat
```
However, using printf works:
```
printf -v m "cat\n" ; m="$m" yq -n '.a = strenv(m)'
printf -v m "cat\n" ; m="$m" yq e -n '.a = strenv(m)'
a: |
cat
```
@@ -31,7 +31,7 @@ a: |
As well as having multiline expressions:
```
m="cat
" yq -n '.a = strenv(m)'
" yq e -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 '.data.values = strenv(output)' first.yml
output=$output ./yq e '.data.values = strenv(output)' first.yml
```
+7 -13
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Map keys
Given a sample.yml file of:
```yaml
@@ -16,7 +10,7 @@ cat: meow
```
then
```bash
yq 'keys' sample.yml
yq eval 'keys' sample.yml
```
will output
```yaml
@@ -32,7 +26,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'keys' sample.yml
yq eval 'keys' sample.yml
```
will output
```yaml
@@ -49,7 +43,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[1] | key' sample.yml
yq eval '.[1] | key' sample.yml
```
will output
```yaml
@@ -63,7 +57,7 @@ a: thing
```
then
```bash
yq '.a | key' sample.yml
yq eval '.a | key' sample.yml
```
will output
```yaml
@@ -77,7 +71,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'key' sample.yml
yq eval 'key' sample.yml
```
will output
```yaml
@@ -92,7 +86,7 @@ a:
```
then
```bash
yq '(.a.x | key) = "meow"' sample.yml
yq eval '(.a.x | key) = "meow"' sample.yml
```
will output
```yaml
@@ -111,7 +105,7 @@ a:
```
then
```bash
yq '.a.x | key | headComment' sample.yml
yq eval '.a.x | key | headComment' sample.yml
```
will output
```yaml
+4 -10
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## String length
returns length of string
@@ -17,7 +11,7 @@ a: cat
```
then
```bash
yq '.a | length' sample.yml
yq eval '.a | length' sample.yml
```
will output
```yaml
@@ -31,7 +25,7 @@ a: null
```
then
```bash
yq '.a | length' sample.yml
yq eval '.a | length' sample.yml
```
will output
```yaml
@@ -48,7 +42,7 @@ c: dog
```
then
```bash
yq 'length' sample.yml
yq eval 'length' sample.yml
```
will output
```yaml
@@ -67,7 +61,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'length' sample.yml
yq eval 'length' sample.yml
```
will output
```yaml
-68
View File
@@ -1,68 +0,0 @@
# Line
Returns the line of the matching node. Starts from 1, 0 indicates there was no line data.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Returns line of _value_ node
Given a sample.yml file of:
```yaml
a: cat
b:
c: cat
```
then
```bash
yq '.b | line' sample.yml
```
will output
```yaml
3
```
## Returns line of _key_ node
Pipe through the key operator to get the line of the key
Given a sample.yml file of:
```yaml
a: cat
b:
c: cat
```
then
```bash
yq '.b | key| line' sample.yml
```
will output
```yaml
2
```
## First line is 1
Given a sample.yml file of:
```yaml
a: cat
```
then
```bash
yq '.a | line' sample.yml
```
will output
```yaml
1
```
## No line data is 0
Running
```bash
yq --null-input '{"a": "new entry"} | line'
```
will output
```yaml
0
```
+7 -113
View File
@@ -1,56 +1,18 @@
# Load
The load operators allows you to load in content from another file.
The `load`/`strload` operator allows you to load in content from another file referenced in your yaml document.
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.
You can load files of the following supported types:
Use `strload` to load text based content as a string block, and `load` to interpret the file as yaml.
|Format | Load Operator |
| --- | --- |
| Yaml | load |
| XML | load_xml |
| Properties | load_props |
| Plain String | load_str |
| Base64 | load_base64 |
## Samples files for tests:
### yaml
`../../examples/thing.yml`:
Lets say there is a file `../../examples/thing.yml`:
```yaml
a: apple is included
b: cool
```
### xml
`small.xml`:
```xml
<this>is some xml</this>
```
### properties
`small.properties`:
```properties
this.is = a properties file
```
### base64
`base64.txt`:
```
bXkgc2VjcmV0IGNoaWxsaSByZWNpcGUgaXMuLi4u
```
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Simple example
Given a sample.yml file of:
```yaml
@@ -58,7 +20,7 @@ myFile: ../../examples/thing.yml
```
then
```bash
yq 'load(.myFile)' sample.yml
yq eval 'load(.myFile)' sample.yml
```
will output
```yaml
@@ -76,7 +38,7 @@ something:
```
then
```bash
yq '.something |= load("../../examples/" + .file)' sample.yml
yq eval '.something |= load("../../examples/" + .file)' sample.yml
```
will output
```yaml
@@ -98,7 +60,7 @@ over:
```
then
```bash
yq '(.. | select(has("file"))) |= load("../../examples/" + .file)' sample.yml
yq eval '(.. | select(has("file"))) |= load("../../examples/" + .file)' sample.yml
```
will output
```yaml
@@ -121,7 +83,7 @@ something:
```
then
```bash
yq '.something |= load_str("../../examples/" + .file)' sample.yml
yq eval '.something |= strload("../../examples/" + .file)' sample.yml
```
will output
```yaml
@@ -130,71 +92,3 @@ 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
```
## Load from base64 encoded file
Given a sample.yml file of:
```yaml
cool: things
```
then
```bash
yq '.more_stuff = load_base64("../../examples/base64.txt")' sample.yml
```
will output
```yaml
cool: things
more_stuff: my secret chilli recipe is....
```
+2 -8
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Map array
Given a sample.yml file of:
```yaml
@@ -17,7 +11,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'map(. + 1)' sample.yml
yq eval 'map(. + 1)' sample.yml
```
will output
```yaml
@@ -35,7 +29,7 @@ c: 3
```
then
```bash
yq 'map_values(. + 1)' sample.yml
yq eval 'map_values(. + 1)' sample.yml
```
will output
```yaml
+25 -105
View File
@@ -10,10 +10,9 @@ 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
- `+` append arrays
- `d` deeply merge arrays
- `?` only merge _existing_ fields
- `n` only merge _new_ fields
- `+` to append arrays
- `?` to only merge existing fields
- `d` to deeply merge arrays
### Merging files
Note the use of `eval-all` to ensure all documents are loaded into memory.
@@ -22,26 +21,14 @@ 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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Multiply integers
Given a sample.yml file of:
```yaml
a: 3
b: 4
```
then
Running
```bash
yq '.a *= .b' sample.yml
yq eval --null-input '3 * 4'
```
will output
```yaml
a: 12
b: 4
12
```
## Merge objects together, returning merged result only
@@ -57,7 +44,7 @@ b:
```
then
```bash
yq '.a * .b' sample.yml
yq eval '.a * .b' sample.yml
```
will output
```yaml
@@ -80,7 +67,7 @@ b:
```
then
```bash
yq '. * {"a":.b}' sample.yml
yq eval '. * {"a":.b}' sample.yml
```
will output
```yaml
@@ -104,7 +91,7 @@ b:
```
then
```bash
yq '. * {"a":.b}' sample.yml
yq eval '. * {"a":.b}' sample.yml
```
will output
```yaml
@@ -127,7 +114,7 @@ b:
```
then
```bash
yq '. * {"a":.b}' sample.yml
yq eval '. * {"a":.b}' sample.yml
```
will output
```yaml
@@ -153,7 +140,7 @@ b:
```
then
```bash
yq '.a *? .b' sample.yml
yq eval '.a *? .b' sample.yml
```
will output
```yaml
@@ -161,27 +148,6 @@ 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
@@ -200,7 +166,7 @@ b:
```
then
```bash
yq '.a *+ .b' sample.yml
yq eval '.a *+ .b' sample.yml
```
will output
```yaml
@@ -230,7 +196,7 @@ b:
```
then
```bash
yq '.a *?+ .b' sample.yml
yq eval '.a *?+ .b' sample.yml
```
will output
```yaml
@@ -257,7 +223,7 @@ b:
```
then
```bash
yq '.a *d .b' sample.yml
yq eval '.a *d .b' sample.yml
```
will output
```yaml
@@ -268,23 +234,18 @@ 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 the idPath, the unique field we want to merge by.
First the expression will create a map from the arrays keyed by '.a', 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)
@@ -301,7 +262,7 @@ something: else
```
And another sample another.yml file of:
```yaml
newArray:
myArray:
- a: banana
c: bananaC
- a: apple
@@ -311,12 +272,12 @@ newArray:
```
then
```bash
idPath=".a" originalPath=".myArray" otherPath=".newArray" yq eval-all '
yq eval-all '
(
(( (eval(strenv(originalPath)) + eval(strenv(otherPath))) | .[] | {(eval(strenv(idPath))): .}) as $item ireduce ({}; . * $item )) as $uniqueMap
((.myArray[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
) as $mergedArray
| select(fi == 0) | (eval(strenv(originalPath))) = $mergedArray
| select(fi == 0) | .myArray = $mergedArray
' sample.yml another.yml
```
will output
@@ -342,7 +303,7 @@ b: dog
```
then
```bash
yq '. * {"a": {"c": .a}}' sample.yml
yq eval '. * {"a": {"c": .a}}' sample.yml
```
will output
```yaml
@@ -363,7 +324,7 @@ c:
```
then
```bash
yq '.c * .b' sample.yml
yq eval '.c * .b' sample.yml
```
will output
```yaml
@@ -383,7 +344,7 @@ c:
```
then
```bash
yq '.c * .a' sample.yml
yq eval '.c * .a' sample.yml
```
will output
```yaml
@@ -415,7 +376,7 @@ foobar:
```
then
```bash
yq '.foobar * .foobarList' sample.yml
yq eval '.foobar * .foobarList' sample.yml
```
will output
```yaml
@@ -427,44 +388,3 @@ 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
```
+3 -9
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Simple example
Given a sample.yml file of:
```yaml
@@ -16,7 +10,7 @@ a:
```
then
```bash
yq '.a.nested | parent' sample.yml
yq eval '.a.nested | parent' sample.yml
```
will output
```yaml
@@ -35,7 +29,7 @@ b:
```
then
```bash
yq '.. | select(. == "banana") | parent' sample.yml
yq eval '.. | select(. == "banana") | parent' sample.yml
```
will output
```yaml
@@ -50,7 +44,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'parent' sample.yml
yq eval 'parent' sample.yml
```
will output
```yaml
+5 -11
View File
@@ -4,12 +4,6 @@ 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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Map path
Given a sample.yml file of:
```yaml
@@ -18,7 +12,7 @@ a:
```
then
```bash
yq '.a.b | path' sample.yml
yq eval '.a.b | path' sample.yml
```
will output
```yaml
@@ -34,7 +28,7 @@ a:
```
then
```bash
yq '.a.b | path | .[-1]' sample.yml
yq eval '.a.b | path | .[-1]' sample.yml
```
will output
```yaml
@@ -50,7 +44,7 @@ a:
```
then
```bash
yq '.a.[] | select(. == "dog") | path' sample.yml
yq eval '.a.[] | select(. == "dog") | path' sample.yml
```
will output
```yaml
@@ -67,7 +61,7 @@ a:
```
then
```bash
yq '.a.[] | select(. == "dog") | path | .[-1]' sample.yml
yq eval '.a.[] | select(. == "dog") | path | .[-1]' sample.yml
```
will output
```yaml
@@ -84,7 +78,7 @@ a:
```
then
```bash
yq '.a[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml
yq eval '.a[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml
```
will output
```yaml
-53
View File
@@ -1,53 +0,0 @@
# Pick
Filter a map by the specified list of keys. Map is returned with the key in the order of the pick list.
Similarly, filter an array by the specified list of indices.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Pick keys from map
Note that the order of the keys matches the pick order and non existent keys are skipped.
Given a sample.yml file of:
```yaml
myMap:
cat: meow
dog: bark
thing: hamster
hamster: squeek
```
then
```bash
yq '.myMap |= pick(["hamster", "cat", "goat"])' sample.yml
```
will output
```yaml
myMap:
hamster: squeek
cat: meow
```
## Pick indices from array
Note that the order of the indexes matches the pick order and non existent indexes are skipped.
Given a sample.yml file of:
```yaml
- cat
- leopard
- lion
```
then
```bash
yq 'pick([2, 0, 734, -5])' sample.yml
```
will output
```yaml
- lion
- cat
```
+2 -8
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Simple Pipe
Given a sample.yml file of:
```yaml
@@ -16,7 +10,7 @@ a:
```
then
```bash
yq '.a | .b' sample.yml
yq eval '.a | .b' sample.yml
```
will output
```yaml
@@ -32,7 +26,7 @@ c: same
```
then
```bash
yq '.a = "cat" | .b = "dog"' sample.yml
yq eval '.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 '.. style= "flow"' file.yaml
yq eval '.. style= "flow"' file.yaml
```
## match values and map keys form `...`
@@ -17,14 +17,8 @@ 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 '... style= "flow"' file.yaml
yq eval '... style= "flow"' file.yaml
```
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Recurse map (values only)
Given a sample.yml file of:
```yaml
@@ -32,7 +26,7 @@ a: frog
```
then
```bash
yq '..' sample.yml
yq eval '..' sample.yml
```
will output
```yaml
@@ -53,7 +47,7 @@ a:
```
then
```bash
yq '[.. | select(has("name"))]' sample.yml
yq eval '[.. | select(has("name"))]' sample.yml
```
will output
```yaml
@@ -76,7 +70,7 @@ a:
```
then
```bash
yq '.. | select(. == "frog")' sample.yml
yq eval '.. | select(. == "frog")' sample.yml
```
will output
```yaml
@@ -93,7 +87,7 @@ a: frog
```
then
```bash
yq '...' sample.yml
yq eval '...' sample.yml
```
will output
```yaml
@@ -111,7 +105,7 @@ b: *cat
```
then
```bash
yq '[..]' sample.yml
yq eval '[..]' sample.yml
```
will output
```yaml
@@ -148,7 +142,7 @@ foobar:
```
then
```bash
yq '.foobar | [..]' sample.yml
yq eval '.foobar | [..]' sample.yml
```
will output
```yaml
+2 -8
View File
@@ -21,12 +21,6 @@ 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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Sum numbers
Given a sample.yml file of:
```yaml
@@ -37,7 +31,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] as $item ireduce (0; . + $item)' sample.yml
yq eval '.[] as $item ireduce (0; . + $item)' sample.yml
```
will output
```yaml
@@ -73,7 +67,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] as $item ireduce ({}; .[$item | .name] = ($item | .has) )' sample.yml
yq eval '.[] as $item ireduce ({}; .[$item | .name] = ($item | .has) )' sample.yml
```
will output
```yaml
-48
View File
@@ -1,48 +0,0 @@
# Reverse
Reverses the order of the items in an array
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Reverse
Given a sample.yml file of:
```yaml
- 1
- 2
- 3
```
then
```bash
yq 'reverse' sample.yml
```
will output
```yaml
- 3
- 2
- 1
```
## Sort descending by string field
Use sort with reverse to sort in descending order.
Given a sample.yml file of:
```yaml
- a: banana
- a: cat
- a: apple
```
then
```bash
yq 'sort_by(.a) | reverse' sample.yml
```
will output
```yaml
- a: cat
- a: banana
- a: apple
```
+4 -102
View File
@@ -2,13 +2,7 @@
Select is used to filter arrays and maps by a boolean expression.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Select elements from array using wildcard prefix
## Select elements from array
Given a sample.yml file of:
```yaml
- cat
@@ -17,7 +11,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | select(. == "*at")' sample.yml
yq eval '.[] | select(. == "*at")' sample.yml
```
will output
```yaml
@@ -25,99 +19,7 @@ cat
goat
```
## 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.
## Select and update matching values in map
Given a sample.yml file of:
```yaml
a:
@@ -127,7 +29,7 @@ a:
```
then
```bash
yq '(.a.[] | select(. == "cat" or . == "goat")) |= "rabbit"' sample.yml
yq eval '(.a.[] | select(. == "*at")) |= "rabbit"' sample.yml
```
will output
```yaml
+4 -12
View File
@@ -5,19 +5,11 @@ 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 -i -P 'sort_keys(..)' file1.yml
yq -i -P 'sort_keys(..)' file2.yml
yq eval -i -P 'sort_keys(..)' file1.yml
yq eval -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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Sort keys of map
Given a sample.yml file of:
```yaml
@@ -27,7 +19,7 @@ b: bing
```
then
```bash
yq 'sort_keys(.)' sample.yml
yq eval 'sort_keys(.)' sample.yml
```
will output
```yaml
@@ -57,7 +49,7 @@ aParent:
```
then
```bash
yq 'sort_keys(..)' sample.yml
yq eval 'sort_keys(..)' sample.yml
```
will output
```yaml
+6 -35
View File
@@ -2,17 +2,8 @@
Sorts an array. Use `sort` to sort an array as is, or `sort_by(exp)` to sort by a particular expression (e.g. subfield).
To sort by descending order, pipe the results through the `reverse` operator after sorting.
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Sort by string field
Given a sample.yml file of:
```yaml
@@ -22,7 +13,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'sort_by(.a)' sample.yml
yq eval 'sort_by(.a)' sample.yml
```
will output
```yaml
@@ -31,26 +22,6 @@ will output
- a: cat
```
## Sort descending by string field
Use sort with reverse to sort in descending order.
Given a sample.yml file of:
```yaml
- a: banana
- a: cat
- a: apple
```
then
```bash
yq 'sort_by(.a) | reverse' sample.yml
```
will output
```yaml
- a: cat
- a: banana
- a: apple
```
## Sort array in place
Given a sample.yml file of:
```yaml
@@ -61,7 +32,7 @@ cool:
```
then
```bash
yq '.cool |= sort_by(.a)' sample.yml
yq eval '.cool |= sort_by(.a)' sample.yml
```
will output
```yaml
@@ -83,7 +54,7 @@ cool:
```
then
```bash
yq '.cool |= sort_by(keys | .[0])' sample.yml
yq eval '.cool |= sort_by(keys | .[0])' sample.yml
```
will output
```yaml
@@ -109,7 +80,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'sort_by(.a)' sample.yml
yq eval 'sort_by(.a)' sample.yml
```
will output
```yaml
@@ -132,7 +103,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'sort_by(.a)' sample.yml
yq eval 'sort_by(.a)' sample.yml
```
will output
```yaml
@@ -154,7 +125,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'sort' sample.yml
yq eval 'sort' sample.yml
```
will output
```yaml
@@ -2,16 +2,10 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Split empty
Running
```bash
yq --null-input 'split_doc'
yq eval --null-input 'splitDoc'
```
will output
```yaml
@@ -26,7 +20,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | split_doc' sample.yml
yq eval '.[] | splitDoc' sample.yml
```
will output
```yaml
+22 -84
View File
@@ -17,13 +17,13 @@ a: |
Using `$( exp )` wont work, as it will trim the trailing new line.
```
m=$(echo "cat\n") yq -n '.a = strenv(m)'
m=$(echo "cat\n") yq e -n '.a = strenv(m)'
a: cat
```
However, using printf works:
```
printf -v m "cat\n" ; m="$m" yq -n '.a = strenv(m)'
printf -v m "cat\n" ; m="$m" yq e -n '.a = strenv(m)'
a: |
cat
```
@@ -31,7 +31,7 @@ a: |
As well as having multiline expressions:
```
m="cat
" yq -n '.a = strenv(m)'
" yq e -n '.a = strenv(m)'
a: |
cat
```
@@ -40,45 +40,7 @@ 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 '.data.values = strenv(output)' first.yml
```
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## To up (upper) case
Works with unicode characters
Given a sample.yml file of:
```yaml
água
```
then
```bash
yq 'upcase' sample.yml
```
will output
```yaml
ÁGUA
```
## To down (lower) case
Works with unicode characters
Given a sample.yml file of:
```yaml
ÁgUA
```
then
```bash
yq 'downcase' sample.yml
```
will output
```yaml
água
output=$output ./yq e '.data.values = strenv(output)' first.yml
```
## Join strings
@@ -92,7 +54,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'join("; ")' sample.yml
yq eval 'join("; ")' sample.yml
```
will output
```yaml
@@ -106,7 +68,7 @@ foo bar foo
```
then
```bash
yq 'match("foo")' sample.yml
yq eval 'match("foo")' sample.yml
```
will output
```yaml
@@ -123,7 +85,7 @@ foo bar FOO
```
then
```bash
yq '[match("(?i)foo"; "g")]' sample.yml
yq eval '[match("(?i)foo"; "g")]' sample.yml
```
will output
```yaml
@@ -137,14 +99,14 @@ will output
captures: []
```
## Match with global capture group
## Match with capture groups
Given a sample.yml file of:
```yaml
abc abc
```
then
```bash
yq '[match("(ab)(c)"; "g")]' sample.yml
yq eval '[match("(abc)+"; "g")]' sample.yml
```
will output
```yaml
@@ -152,22 +114,16 @@ will output
offset: 0
length: 3
captures:
- string: ab
- string: abc
offset: 0
length: 2
- string: c
offset: 2
length: 1
length: 3
- string: abc
offset: 4
length: 3
captures:
- string: ab
- string: abc
offset: 4
length: 2
- string: c
offset: 6
length: 1
length: 3
```
## Match with named capture groups
@@ -177,7 +133,7 @@ foo bar foo foo foo
```
then
```bash
yq '[match("foo (?P<bar123>bar)? foo"; "g")]' sample.yml
yq eval '[match("foo (?P<bar123>bar)? foo"; "g")]' sample.yml
```
will output
```yaml
@@ -206,7 +162,7 @@ xyzzy-14
```
then
```bash
yq 'capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)")' sample.yml
yq eval 'capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)")' sample.yml
```
will output
```yaml
@@ -221,7 +177,7 @@ cat cat
```
then
```bash
yq 'match("cat")' sample.yml
yq eval 'match("cat")' sample.yml
```
will output
```yaml
@@ -238,7 +194,7 @@ cat cat
```
then
```bash
yq '[match("cat"; "g")]' sample.yml
yq eval '[match("cat"; "g")]' sample.yml
```
will output
```yaml
@@ -262,7 +218,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | test("at")' sample.yml
yq eval '.[] | test("at")' sample.yml
```
will output
```yaml
@@ -280,7 +236,7 @@ a: dogs are great
```
then
```bash
yq '.a |= sub("dogs", "cats")' sample.yml
yq eval '.a |= sub("dogs", "cats")' sample.yml
```
will output
```yaml
@@ -298,7 +254,7 @@ b: heat
```
then
```bash
yq '.[] |= sub("(a)", "${1}r")' sample.yml
yq eval '.[] |= sub("(a)", "${1}r")' sample.yml
```
will output
```yaml
@@ -306,24 +262,6 @@ a: cart
b: heart
```
## 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 heat
```
then
```bash
yq '.[] |= sub("(a)", "${1}r")' sample.yml
```
will output
```yaml
a: !horse cart
b: !goat heart
```
## Split strings
Given a sample.yml file of:
```yaml
@@ -331,7 +269,7 @@ cat; meow; 1; ; true
```
then
```bash
yq 'split("; ")' sample.yml
yq eval 'split("; ")' sample.yml
```
will output
```yaml
@@ -349,7 +287,7 @@ word
```
then
```bash
yq 'split("; ")' sample.yml
yq eval 'split("; ")' sample.yml
```
will output
```yaml
+12 -18
View File
@@ -2,12 +2,6 @@
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.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Update and set style of a particular node (simple)
Given a sample.yml file of:
```yaml
@@ -17,7 +11,7 @@ a:
```
then
```bash
yq '.a.b = "new" | .a.b style="double"' sample.yml
yq eval '.a.b = "new" | .a.b style="double"' sample.yml
```
will output
```yaml
@@ -35,7 +29,7 @@ a:
```
then
```bash
yq 'with(.a.b ; . = "new" | . style="double")' sample.yml
yq eval 'with(.a.b ; . = "new" | . style="double")' sample.yml
```
will output
```yaml
@@ -54,7 +48,7 @@ e: true
```
then
```bash
yq '.. style="tagged"' sample.yml
yq eval '.. style="tagged"' sample.yml
```
will output
```yaml
@@ -75,7 +69,7 @@ e: true
```
then
```bash
yq '.. style="double"' sample.yml
yq eval '.. style="double"' sample.yml
```
will output
```yaml
@@ -95,7 +89,7 @@ e: true
```
then
```bash
yq '... style="double"' sample.yml
yq eval '... style="double"' sample.yml
```
will output
```yaml
@@ -115,7 +109,7 @@ e: true
```
then
```bash
yq '.. style="single"' sample.yml
yq eval '.. style="single"' sample.yml
```
will output
```yaml
@@ -135,7 +129,7 @@ e: true
```
then
```bash
yq '.. style="literal"' sample.yml
yq eval '.. style="literal"' sample.yml
```
will output
```yaml
@@ -159,7 +153,7 @@ e: true
```
then
```bash
yq '.. style="folded"' sample.yml
yq eval '.. style="folded"' sample.yml
```
will output
```yaml
@@ -183,7 +177,7 @@ e: true
```
then
```bash
yq '.. style="flow"' sample.yml
yq eval '.. style="flow"' sample.yml
```
will output
```yaml
@@ -202,7 +196,7 @@ a: cat
```
then
```bash
yq '... style=""' sample.yml
yq eval '... style=""' sample.yml
```
will output
```yaml
@@ -220,7 +214,7 @@ b: double
```
then
```bash
yq '.[] style |= .' sample.yml
yq eval '.[] style |= .' sample.yml
```
will output
```yaml
@@ -235,7 +229,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.. | style' sample.yml
yq eval '.. | style' sample.yml
```
will output
```yaml

Some files were not shown because too many files have changed in this diff Show More