1
0
mirror of https://github.com/taigrr/yq synced 2025-01-18 04:53:17 -08:00

Compare commits

...

8 Commits
3.3.1 ... v2.x

Author SHA1 Message Date
Mike Farah
767208871b GitBook: [v2.x] 10 pages modified 2020-06-16 01:19:03 +00:00
Mike Farah
086f0ec6b9 Update bug_report.md 2020-06-15 21:42:26 +10:00
Mike Farah
89cbe63343 Fixed deep read at root level 2020-06-15 12:31:13 +10:00
RyderXia
07cd3d4b8b return error 2020-06-13 16:45:52 +10:00
RyderXia
b7b6988e76 mk TempDir 2020-06-13 16:45:52 +10:00
Mike Farah
9de2039c31 Version bump 2020-06-12 12:23:18 +10:00
Mike Farah
767709fef5 Fixed error flag 2020-06-12 12:21:46 +10:00
Mike Farah
d9ae8e1e5a Updated readme 2020-06-12 09:30:05 +10:00
22 changed files with 1535 additions and 151 deletions

View File

@@ -0,0 +1,60 @@
## Yaml to Json
To convert output to json, use the --tojson (or -j) flag. This is supported by all commands.
Each matching yaml node will be converted to json and printed out on a separate line.
Given a sample.yaml file of:
```yaml
b:
c: 2
```
then
```bash
yq r -j sample.yaml
```
will output
```json
{"b":{"c":2}}
```
Given a sample.yaml file of:
```yaml
bob:
c: 2
bab:
c: 5
```
then
```bash
yq r -j sample.yaml b*
```
will output
```json
{"c":2}
{"c":5}
```
## Json to Yaml
To read in json, just pass in a json file instead of yaml, it will just work :)
e.g given a json file
```json
{"a":"Easy! as one two three","b":{"c":2,"d":[3,4]}}
```
then
```bash
yq r sample.json
```
will output
```yaml
a: Easy! as one two three
b:
c: 2
d:
- 3
- 4
```

View File

@@ -10,6 +10,9 @@ assignees: ''
**Describe the bug** **Describe the bug**
A clear and concise description of what the bug is. A clear and concise description of what the bug is.
version of yq:
operating system:
**Input Yaml** **Input Yaml**
Concise yaml document(s) (as simple as possible to show the bug) Concise yaml document(s) (as simple as possible to show the bug)
data1.yml: data1.yml:

131
README.md
View File

@@ -1,135 +1,36 @@
# yq ---
description: yq is a lightweight and portable command-line YAML processor
---
![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) # Yq
### Install[¶]() <a id="install"></a>
a lightweight and portable command-line YAML processor On MacOS:
The aim of the project is to be the [jq](https://github.com/stedolan/jq) or sed of yaml files. ```text
## New version!
V3 is officially out - if you've been using v2 and want/need to upgrade, checkout the [upgrade guide](https://mikefarah.gitbook.io/yq/upgrading-from-v2).
## Install
### [Download the latest binary](https://github.com/mikefarah/yq/releases/latest)
### MacOS:
```
brew install yq brew install yq
``` ```
### Windows: On Ubuntu and other Linux distros supporting `snap` packages:
```
choco install yq
```
Supported by @chillum
### Ubuntu and other Linux distros supporting `snap` packages: ```text
```
snap install yq snap install yq
``` ```
#### Snap notes On Ubuntu 16.04 or higher from Debian package:
`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:
``` ```text
sudo cat /etc/myfile | yq r - 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 w - a.path value | sudo sponge /etc/myfile
```
or write to a temporary file:
```
sudo cat /etc/myfile | yq w - a.path value | sudo tee /etc/myfile.tmp
sudo mv /etc/myfile.tmp /etc/myfile
rm /etc/myfile.tmp
```
### On Ubuntu 16.04 or higher from Debian package:
```sh
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys CC86BB64
sudo add-apt-repository ppa:rmescandon/yq sudo add-apt-repository ppa:rmescandon/yq
sudo apt update sudo apt update
sudo apt install yq -y sudo apt install yq -y
``` ```
Supported by @rmescandon
### Go Get: or, [Download latest binary](https://github.com/mikefarah/yq/releases/latest) or alternatively:
```
GO111MODULE=on go get github.com/mikefarah/yq/v3 ```text
GO111MODULE=on go get github.com/mikefarah/yq/v2
``` ```
## Run with Docker [View on GitHub](https://github.com/mikefarah/yq)
Oneshot use:
```bash
docker run --rm -v "${PWD}":/workdir mikefarah/yq yq [flags] <command> FILE...
```
Run commands interactively:
```bash
docker run --rm -it -v "${PWD}":/workdir mikefarah/yq sh
```
It can be useful to have a bash function to avoid typing the whole docker command:
```bash
yq() {
docker run --rm -i -v "${PWD}":/workdir mikefarah/yq yq "$@"
}
```
## Features
- Written in portable go, so you can download a lovely dependency free binary
- [Colorize the output](https://mikefarah.gitbook.io/yq/usage/output-format#colorize-output)
- [Deep read a yaml file with a given path expression](https://mikefarah.gitbook.io/yq/commands/read#basic)
- [List matching paths of a given path expression](https://mikefarah.gitbook.io/yq/commands/read#path-only)
- [Return the lengths of arrays/object/scalars](https://mikefarah.gitbook.io/yq/commands/read#printing-length-of-the-results)
- Update a yaml file given a [path expression](https://mikefarah.gitbook.io/yq/commands/write-update#basic) or [script file](https://mikefarah.gitbook.io/yq/commands/write-update#basic)
- Update creates any missing entries in the path on the fly
- Deeply [compare](https://mikefarah.gitbook.io/yq/commands/compare) yaml files
- Keeps yaml formatting and comments when updating
- [Validate a yaml file](https://mikefarah.gitbook.io/yq/commands/validate)
- Create a yaml file given a [deep path and value](https://mikefarah.gitbook.io/yq/commands/create#creating-a-simple-yaml-file) or a [script file](https://mikefarah.gitbook.io/yq/commands/create#creating-using-a-create-script)
- [Prefix a path to a yaml file](https://mikefarah.gitbook.io/yq/commands/prefix)
- [Convert to/from json to yaml](https://mikefarah.gitbook.io/yq/usage/convert)
- [Pipe data in by using '-'](https://mikefarah.gitbook.io/yq/commands/read#from-stdin)
- [Merge](https://mikefarah.gitbook.io/yq/commands/merge) multiple yaml files with various options for [overriding](https://mikefarah.gitbook.io/yq/commands/merge#overwrite-values) and [appending](https://mikefarah.gitbook.io/yq/commands/merge#append-values-with-arrays)
- Supports multiple documents in a single yaml file for [reading](https://mikefarah.gitbook.io/yq/commands/read#multiple-documents), [writing](https://mikefarah.gitbook.io/yq/commands/write-update#multiple-documents) and [merging](https://mikefarah.gitbook.io/yq/commands/merge#multiple-documents)
## [Usage](https://mikefarah.gitbook.io/yq/)
Check out the [documentation](https://mikefarah.gitbook.io/yq/) for more detailed and advanced usage.
```
Usage:
yq [flags]
yq [command]
Available Commands:
compare yq x [--prettyPrint/-P] dataA.yaml dataB.yaml 'b.e(name==fr*).value'
delete yq d [--inplace/-i] [--doc/-d index] sample.yaml 'b.e(name==fred)'
help Help about any command
merge yq m [--inplace/-i] [--doc/-d index] [--overwrite/-x] [--append/-a] sample.yaml sample2.yaml
new yq n [--script/-s script_file] a.b.c newValue
prefix yq p [--inplace/-i] [--doc/-d index] sample.yaml a.b.c
read yq r [--printMode/-p pv] sample.yaml 'b.e(name==fr*).value'
validate yq v sample.yaml
write yq w [--inplace/-i] [--script/-s script_file] [--doc/-d index] sample.yaml 'b.e(name==fr*).value' newValue
Flags:
-C, --colors print using colors
-h, --help help for yq
-I, --indent int sets indent level for output (default 2)
-P, --prettyPrint pretty print
-j, --tojson output as json. By default it prints a json document in one line, use the prettyPrint flag to print a formatted doc.
-v, --verbose verbose mode
-V, --version Print version information and quit
Use "yq [command] --help" for more information about a command.
```

11
SUMMARY.md Normal file
View File

@@ -0,0 +1,11 @@
# Table of contents
* [Yq](README.md)
* [Write](write-update.md)
* [Read](read.md)
* [Prefix](prefix.md)
* [Delete](delete.md)
* [Create](create.md)
* [Convert](convert.md)
* [Merge](merge.md)

View File

@@ -51,7 +51,7 @@ func readProperty(cmd *cobra.Command, args []string) error {
matchingNodes, errorReadingStream := readYamlFile(args[0], path, updateAll, docIndexInt) matchingNodes, errorReadingStream := readYamlFile(args[0], path, updateAll, docIndexInt)
if exitStatus { if exitStatus && len(matchingNodes) == 0 {
cmd.SilenceUsage = true cmd.SilenceUsage = true
return errors.New("No matches found") return errors.New("No matches found")
} }

View File

@@ -17,6 +17,30 @@ func TestReadCmd(t *testing.T) {
test.AssertResult(t, "2\n", result.Output) test.AssertResult(t, "2\n", result.Output)
} }
func TestReadCmdWithExitStatus(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "read ../examples/sample.yaml b.c -e")
if result.Error != nil {
t.Error(result.Error)
}
test.AssertResult(t, "2\n", result.Output)
}
func TestReadCmdWithExitStatusNotExist(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "read ../examples/sample.yaml caterpillar -e")
test.AssertResult(t, "No matches found", result.Error.Error())
}
func TestReadCmdNotExist(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "read ../examples/sample.yaml caterpillar")
if result.Error != nil {
t.Error(result.Error)
}
test.AssertResult(t, "", result.Output)
}
func TestReadUnwrapCmd(t *testing.T) { func TestReadUnwrapCmd(t *testing.T) {
content := `b: 'frog' # my favourite` content := `b: 'frog' # my favourite`
@@ -1183,6 +1207,26 @@ func TestReadBadDataCmd(t *testing.T) {
test.AssertResult(t, expectedOutput, result.Error.Error()) test.AssertResult(t, expectedOutput, result.Error.Error())
} }
func TestReadDeepFromRootCmd(t *testing.T) {
content := `state:
country:
city: foo
`
filename := test.WriteTempYamlFile(content)
defer test.RemoveTempYamlFile(filename)
cmd := getRootCommand()
result := test.RunCmd(cmd, fmt.Sprintf("read %s (**.city==foo)", filename))
if result.Error != nil {
t.Error(result.Error)
}
expectedOutput := `country:
city: foo
`
test.AssertResult(t, expectedOutput, result.Output)
}
func TestReadSplatPrefixCmd(t *testing.T) { func TestReadSplatPrefixCmd(t *testing.T) {
content := `a: 2 content := `a: 2
b: b:

View File

@@ -16,13 +16,13 @@ func createBashCompletionCmd(rootCmd *cobra.Command) *cobra.Command {
Long: `To load completion for: Long: `To load completion for:
bash: bash:
Run Run
. <(yq bash-completion) . <(yq shell-completion)
To configure your bash shell to load completions for each session add to To configure your bash shell to load completions for each session add to
your bashrc your bashrc
# ~/.bashrc or ~/.profile # ~/.bashrc or ~/.profile
. <(yq bash-completion) . <(yq shell-completion)
zsh: zsh:
The generated completion script should be put somewhere in your $fpath named _yq The generated completion script should be put somewhere in your $fpath named _yq

View File

@@ -423,6 +423,16 @@ func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn)
if err != nil { if err != nil {
return err return err
} }
// mkdir temp dir as some docker images does not have temp dir
_, err = os.Stat(os.TempDir())
if os.IsNotExist(err) {
err = os.Mkdir(os.TempDir(), 0700)
if err != nil {
return err
}
} else if err != nil {
return err
}
tempFile, err := ioutil.TempFile("", "temp") tempFile, err := ioutil.TempFile("", "temp")
if err != nil { if err != nil {
return err return err

View File

@@ -11,7 +11,7 @@ var (
GitDescribe string GitDescribe string
// Version is main version number that is being run at the moment. // Version is main version number that is being run at the moment.
Version = "3.3.1" Version = "3.3.2"
// VersionPrerelease is a pre-release marker for the version. If this is "" (empty string) // 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 // then it means that it is a final release. Otherwise, this is a pre-release

52
convert.md Normal file
View File

@@ -0,0 +1,52 @@
# Convert
### Yaml to Json[¶](convert.md#yaml-to-json) <a id="yaml-to-json"></a>
To convert output to json, use the --tojson \(or -j\) flag. This can only be used with the read command.
Given a sample.yaml file of:
```text
b:
c: 2
```
then
```text
yq r -j sample.yaml b.c
```
will output
```text
{"b":{"c":2}}
```
### Json to Yaml[¶](convert.md#json-to-yaml) <a id="json-to-yaml"></a>
To read in json, just pass in a json file instead of yaml, it will just work :\)
e.g given a json file
```text
{"a":"Easy! as one two three","b":{"c":2,"d":[3,4]}}
```
then
```text
yq r sample.json
```
will output
```text
a: Easy! as one two three
b:
c: 2
d:
- 3
- 4
```

88
create.md Normal file
View File

@@ -0,0 +1,88 @@
# Create
Yaml files can be created using the 'new' command. This works in the same way as the write command, but you don't pass in an existing Yaml file. Currently this does not support creating multiple documents in a single yaml file.
```text
yq n <path> <new value>
```
### Creating a simple yaml file[¶](create.md#creating-a-simple-yaml-file) <a id="creating-a-simple-yaml-file"></a>
```text
yq n b.c cat
```
will output:
```text
b:
c: cat
```
### Creating using a create script[¶](create.md#creating-using-a-create-script) <a id="creating-using-a-create-script"></a>
Create scripts follow the same format as the update scripts.
Given a script create\_instructions.yaml of:
```text
b.c: 3
b.e[+].name: Howdy Partner
```
then
```text
yq n -s create_instructions.yaml
```
will output:
```text
b:
c: 3
e:
- name: Howdy Partner
```
You can also pipe the instructions in:
```text
cat create_instructions.yaml | yq n -s -
```
### Keys with dots[¶](create.md#keys-with-dots) <a id="keys-with-dots"></a>
When specifying a key that has a dot use key lookup indicator.
```text
b:
foo.bar: 7
```
```text
yaml r sample.yaml 'b[foo.bar]'
```
```text
yaml w sample.yaml 'b[foo.bar]' 9
```
Any valid yaml key can be specified as part of a key lookup.
Note that the path is in quotes to avoid the square brackets being interpreted by your shell.
### Keys \(and values\) with leading dashes[¶](create.md#keys-and-values-with-leading-dashes) <a id="keys-and-values-with-leading-dashes"></a>
If a key or value has leading dashes, yq won't know that you are passing a value as opposed to a flag \(and you will get a 'bad flag syntax' error\).
To fix that, you will need to tell it to stop processing flags by adding '--' after the last flag like so:
```text
yq n -t -- --key --value
```
Will result in
``` --key: --value``

280
delete.md Normal file
View File

@@ -0,0 +1,280 @@
# Delete
```text
yq d <yaml_file> <path_to_delete>
```
### To Stdout[¶](delete.md#to-stdout) <a id="to-stdout"></a>
Given a sample.yaml file of:
```text
b:
c: 2
apples: green
```
then
```text
yq d sample.yaml b.c
```
will output:
```text
b:
apples: green
```
### From STDIN[¶](delete.md#from-stdin) <a id="from-stdin"></a>
```text
cat sample.yaml | yq d - b.c
```
### Deleting array elements[¶](delete.md#deleting-array-elements) <a id="deleting-array-elements"></a>
Given a sample.yaml file of:
```text
b:
c:
- 1
- 2
- 3
```
then
```text
yq d sample.yaml 'b.c[1]'
```
will output:
```text
b:
c:
- 1
- 3
```
### Deleting nodes in-place[¶](delete.md#deleting-nodes-in-place) <a id="deleting-nodes-in-place"></a>
Given a sample.yaml file of:
```text
b:
c: 2
apples: green
```
then
```text
yq d -i sample.yaml b.c
```
will update the sample.yaml file so that the 'c' node is deleted
### Splat[¶](delete.md#splat) <a id="splat"></a>
Given a sample.yaml file of:
```text
---
bob:
item1:
cats: bananas
dogs: woof
item2:
cats: apples
dogs: woof2
thing:
cats: oranges
dogs: woof3
```
then
```text
yq d sample.yaml bob.*.cats
```
will output:
```text
---
bob:
item1:
dogs: woof
item2:
dogs: woof2
thing:
dogs: woof3
```
### Prefix Splat[¶](delete.md#prefix-splat) <a id="prefix-splat"></a>
Given a sample.yaml file of:
```text
---
bob:
item1:
cats: bananas
dogs: woof
item2:
cats: apples
dogs: woof2
thing:
cats: oranges
dogs: woof3
```
then
```text
yq d sample.yaml bob.item*.cats
```
will output:
```text
---
bob:
item1:
dogs: woof
item2:
dogs: woof2
thing:
cats: oranges
dogs: woof3
```
### Array Splat[¶](delete.md#array-splat) <a id="array-splat"></a>
Given a sample.yaml file of:
```text
---
bob:
- cats: bananas
dogs: woof
- cats: apples
dogs: woof2
- cats: oranges
dogs: woof3
```
then
```text
yq d sample.yaml bob.[*].cats
```
will output:
```text
---
bob:
- dogs: woof
- dogs: woof2
- dogs: woof3
```
### Multiple Documents - delete from single document[¶](delete.md#multiple-documents-delete-from-single-document) <a id="multiple-documents-delete-from-single-document"></a>
Given a sample.yaml file of:
```text
something: else
field: leaveMe
---
b:
c: 2
field: deleteMe
```
then
```text
yq w -d1 sample.yaml field
```
will output:
```text
something: else
field: leaveMe
---
b:
c: 2
```
### Multiple Documents - delete from all documents[¶](delete.md#multiple-documents-delete-from-all-documents) <a id="multiple-documents-delete-from-all-documents"></a>
Given a sample.yaml file of:
```text
something: else
field: deleteMe
---
b:
c: 2
field: deleteMeToo
```
then
```text
yq w -d'*' sample.yaml field
```
will output:
```text
something: else
---
b:
c: 2
```
Note that '\*' is in quotes to avoid being interpreted by your shell.
### Keys with dots[¶](delete.md#keys-with-dots) <a id="keys-with-dots"></a>
When specifying a key that has a dot use key lookup indicator.
```text
b:
foo.bar: 7
```
```text
yaml r sample.yaml 'b[foo.bar]'
```
```text
yaml w sample.yaml 'b[foo.bar]' 9
```
Any valid yaml key can be specified as part of a key lookup.
Note that the path is in quotes to avoid the square brackets being interpreted by your shell.
### Keys \(and values\) with leading dashes[¶](delete.md#keys-and-values-with-leading-dashes) <a id="keys-and-values-with-leading-dashes"></a>
If a key or value has leading dashes, yq won't know that you are passing a value as opposed to a flag \(and you will get a 'bad flag syntax' error\).
To fix that, you will need to tell it to stop processing flags by adding '--' after the last flag like so:
```text
yq n -t -- --key --value
```
Will result in
``` --key: --value``

245
merge.md Normal file
View File

@@ -0,0 +1,245 @@
# Merge
Yaml files can be merged using the 'merge' command. Each additional file merged with the first file will set values for any key not existing already or where the key has no value.
```text
yq m <yaml_file> <path>...
```
### To Stdout[¶](merge.md#to-stdout) <a id="to-stdout"></a>
Given a data1.yaml file of:
```text
a: simple
b: [1, 2]
```
and data2.yaml file of:
```text
a: other
c:
test: 1
```
then
```text
yq m data1.yaml data2.yaml
```
will output:
```text
a: simple
b: [1, 2]
c:
test: 1
```
### Updating files in-place[¶](merge.md#updating-files-in-place) <a id="updating-files-in-place"></a>
Given a data1.yaml file of:
```text
a: simple
b: [1, 2]
```
and data2.yaml file of:
```text
a: other
c:
test: 1
```
then
```text
yq m -i data1.yaml data2.yaml
```
will update the data1.yaml file so that the value of 'c' is 'test: 1'.
### Overwrite values[¶](merge.md#overwrite-values) <a id="overwrite-values"></a>
Given a data1.yaml file of:
```text
a: simple
b: [1, 2]
```
and data2.yaml file of:
```text
a: other
c:
test: 1
```
then
```text
yq m -x data1.yaml data2.yaml
```
will output:
```text
a: other
b: [1, 2]
c:
test: 1
```
### Overwrite values with arrays[¶](merge.md#overwrite-values-with-arrays) <a id="overwrite-values-with-arrays"></a>
Given a data1.yaml file of:
```text
a: simple
b: [1, 2]
```
and data3.yaml file of:
```text
b: [3, 4]
c:
test: 2
other: true
d: false
```
then
```text
yq m -x data1.yaml data3.yaml
```
will output:
```text
a: simple
b: [3, 4]
c:
test: 2
other: true
d: false
```
Notice that 'b' does not result in the merging of the values within an array.
### Append values with arrays[¶](merge.md#append-values-with-arrays) <a id="append-values-with-arrays"></a>
Given a data1.yaml file of:
```text
a: simple
b: [1, 2]
d: hi
```
and data3.yaml file of:
```text
a: something
b: [3, 4]
c:
test: 2
other: true
```
then
```text
yq m -a data1.yaml data3.yaml
```
will output:
```text
a: simple
b: [1, 2, 3, 4]
c:
test: 2
other: true
d: hi
```
Note that the 'b' array has concatenated the values from the second data file. Also note that other map keys are not overridden \(field a\).
Append cannot be used with overwrite, if both flags are given then append is ignored.
### Multiple Documents - merge into single document[¶](merge.md#multiple-documents-merge-into-single-document) <a id="multiple-documents-merge-into-single-document"></a>
Currently yq only has multi-document support for the _first_ document being merged into. The remaining yaml files will have their first document selected.
Given a data1.yaml file of:
```text
something: else
---
a: simple
b: cat
```
and data3.yaml file of:
```text
b: dog
```
then
```text
yq m -x -d1 data1.yaml data3.yaml
```
will output:
```text
something: else
---
a: simple
b: dog
```
### Multiple Documents - merge into all documents[¶](merge.md#multiple-documents-merge-into-all-documents) <a id="multiple-documents-merge-into-all-documents"></a>
Currently yq only has multi-document support for the _first_ document being merged into. The remaining yaml files will have their first document selected.
Given a data1.yaml file of:
```text
something: else
---
a: simple
b: cat
```
and data3.yaml file of:
```text
b: dog
```
then
```text
yq m -x -d'*' data1.yaml data3.yaml
```
will output:
```text
b: dog
something: else
---
a: simple
b: dog
```

View File

@@ -12,12 +12,6 @@ func DeleteNavigationStrategy(pathElementToDelete interface{}) NavigationStrateg
followAlias: func(nodeContext NodeContext) bool { followAlias: func(nodeContext NodeContext) bool {
return false return false
}, },
autoCreateMap: func(nodeContext NodeContext) bool {
return false
},
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
return true
},
shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool { shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool {
return false return false
}, },

View File

@@ -4,12 +4,6 @@ func FilterMatchingNodesNavigationStrategy(value string) NavigationStrategy {
return &NavigationStrategyImpl{ return &NavigationStrategyImpl{
visitedNodes: []*NodeContext{}, visitedNodes: []*NodeContext{},
pathParser: NewPathParser(), pathParser: NewPathParser(),
followAlias: func(nodeContext NodeContext) bool {
return true
},
autoCreateMap: func(nodeContext NodeContext) bool {
return false
},
visit: func(nodeContext NodeContext) error { visit: func(nodeContext NodeContext) error {
return nil return nil
}, },

View File

@@ -62,19 +62,32 @@ func (ns *NavigationStrategyImpl) GetVisitedNodes() []*NodeContext {
} }
func (ns *NavigationStrategyImpl) FollowAlias(nodeContext NodeContext) bool { func (ns *NavigationStrategyImpl) FollowAlias(nodeContext NodeContext) bool {
return ns.followAlias(nodeContext) if ns.followAlias != nil {
return ns.followAlias(nodeContext)
}
return true
} }
func (ns *NavigationStrategyImpl) AutoCreateMap(nodeContext NodeContext) bool { func (ns *NavigationStrategyImpl) AutoCreateMap(nodeContext NodeContext) bool {
return ns.autoCreateMap(nodeContext) if ns.autoCreateMap != nil {
return ns.autoCreateMap(nodeContext)
}
return false
} }
func (ns *NavigationStrategyImpl) ShouldDeeplyTraverse(nodeContext NodeContext) bool { func (ns *NavigationStrategyImpl) ShouldDeeplyTraverse(nodeContext NodeContext) bool {
return ns.shouldDeeplyTraverse(nodeContext) if ns.shouldDeeplyTraverse != nil {
return ns.shouldDeeplyTraverse(nodeContext)
}
return true
} }
func (ns *NavigationStrategyImpl) ShouldOnlyDeeplyVisitLeaves(nodeContext NodeContext) bool { func (ns *NavigationStrategyImpl) ShouldOnlyDeeplyVisitLeaves(nodeContext NodeContext) bool {
return ns.shouldOnlyDeeplyVisitLeaves(nodeContext) if ns.shouldOnlyDeeplyVisitLeaves != nil {
return ns.shouldOnlyDeeplyVisitLeaves(nodeContext)
}
return true
} }
func (ns *NavigationStrategyImpl) ShouldTraverse(nodeContext NodeContext, nodeKey string) bool { func (ns *NavigationStrategyImpl) ShouldTraverse(nodeContext NodeContext, nodeKey string) bool {

View File

@@ -4,12 +4,6 @@ func ReadNavigationStrategy(deeplyTraverseArrays bool) NavigationStrategy {
return &NavigationStrategyImpl{ return &NavigationStrategyImpl{
visitedNodes: []*NodeContext{}, visitedNodes: []*NodeContext{},
pathParser: NewPathParser(), pathParser: NewPathParser(),
followAlias: func(nodeContext NodeContext) bool {
return true
},
autoCreateMap: func(nodeContext NodeContext) bool {
return false
},
visit: func(nodeContext NodeContext) error { visit: func(nodeContext NodeContext) error {
return nil return nil
}, },
@@ -26,8 +20,5 @@ func ReadNavigationStrategy(deeplyTraverseArrays bool) NavigationStrategy {
} }
return deeplyTraverseArrays || !isInArray return deeplyTraverseArrays || !isInArray
}, },
shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool {
return true
},
} }
} }

View File

@@ -10,12 +10,6 @@ func UpdateNavigationStrategy(updateCommand UpdateCommand, autoCreate bool) Navi
autoCreateMap: func(nodeContext NodeContext) bool { autoCreateMap: func(nodeContext NodeContext) bool {
return autoCreate return autoCreate
}, },
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
return true
},
shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool {
return true
},
visit: func(nodeContext NodeContext) error { visit: func(nodeContext NodeContext) error {
node := nodeContext.Node node := nodeContext.Node
changesToApply := updateCommand.Value changesToApply := updateCommand.Value

127
prefix.md Normal file
View File

@@ -0,0 +1,127 @@
# Prefix
Paths can be prefixed using the 'prefix' command. The complete yaml content will be nested inside the new prefix path.
```text
yq p <yaml_file> <path>
```
### To Stdout[¶](prefix.md#to-stdout) <a id="to-stdout"></a>
Given a data1.yaml file of:
```text
a: simple
b: [1, 2]
```
then
```text
yq p data1.yaml c
```
will output:
```text
c:
a: simple
b: [1, 2]
```
### Arbitrary depth[¶](prefix.md#arbitrary-depth) <a id="arbitrary-depth"></a>
Given a data1.yaml file of:
```text
a:
b: [1, 2]
```
then
```text
yq p data1.yaml c.d
```
will output:
```text
c:
d:
a:
b: [1, 2]
```
### Updating files in-place[¶](prefix.md#updating-files-in-place) <a id="updating-files-in-place"></a>
Given a data1.yaml file of:
```text
a: simple
b: [1, 2]
```
then
```text
yq p -i data1.yaml c
```
will update the data1.yaml file so that the path 'c' is prefixed to all other paths.
### Multiple Documents - prefix a single document[¶](prefix.md#multiple-documents-prefix-a-single-document) <a id="multiple-documents-prefix-a-single-document"></a>
Given a data1.yaml file of:
```text
something: else
---
a: simple
b: cat
```
then
```text
yq p -d1 data1.yaml c
```
will output:
```text
something: else
---
c:
a: simple
b: cat
```
### Multiple Documents - prefix all documents[¶](prefix.md#multiple-documents-prefix-all-documents) <a id="multiple-documents-prefix-all-documents"></a>
Given a data1.yaml file of:
```text
something: else
---
a: simple
b: cat
```
then
```text
yq p -d'*' data1.yaml c
```
will output:
```text
c:
something: else
---
c:
a: simple
b: cat
```

228
read.md Normal file
View File

@@ -0,0 +1,228 @@
# Read
```text
yq r <yaml_file|json_file> <path>
```
This command can take a json file as input too, and will output yaml unless specified to export as json \(-j\)
### Basic[¶](read.md#basic) <a id="basic"></a>
Given a sample.yaml file of:
```text
b:
c: 2
```
then
```text
yq r sample.yaml b.c
```
will output the value of '2'.
### From Stdin[¶](read.md#from-stdin) <a id="from-stdin"></a>
Given a sample.yaml file of:
```text
cat sample.yaml | yq r - b.c
```
will output the value of '2'.
### Splat[¶](read.md#splat) <a id="splat"></a>
Given a sample.yaml file of:
```text
---
bob:
item1:
cats: bananas
item2:
cats: apples
thing:
cats: oranges
```
then
```text
yq r sample.yaml bob.*.cats
```
will output
```text
- bananas
- apples
- oranges
```
### Prefix Splat[¶](read.md#prefix-splat) <a id="prefix-splat"></a>
Given a sample.yaml file of:
```text
---
bob:
item1:
cats: bananas
item2:
cats: apples
thing:
cats: oranges
```
then
```text
yq r sample.yaml bob.item*.cats
```
will output
```text
- bananas
- apples
```
### Multiple Documents - specify a single document[¶](read.md#multiple-documents-specify-a-single-document) <a id="multiple-documents-specify-a-single-document"></a>
Given a sample.yaml file of:
```text
something: else
---
b:
c: 2
```
then
```text
yq r -d1 sample.yaml b.c
```
will output the value of '2'.
### Multiple Documents - read all documents[¶](read.md#multiple-documents-read-all-documents) <a id="multiple-documents-read-all-documents"></a>
Reading all documents will return the result as an array. This can be converted to json using the '-j' flag if desired.
Given a sample.yaml file of:
```text
name: Fred
age: 22
---
name: Stella
age: 23
---
name: Android
age: 232
```
then
```text
yq r -d'*' sample.yaml name
```
will output:
```text
- Fred
- Stella
- Android
```
### Arrays[¶](read.md#arrays) <a id="arrays"></a>
You can give an index to access a specific element: e.g.: given a sample file of
```text
b:
e:
- name: fred
value: 3
- name: sam
value: 4
```
then
```text
yq r sample.yaml 'b.e[1].name'
```
will output 'sam'
Note that the path is in quotes to avoid the square brackets being interpreted by your shell.
### Array Splat[¶](read.md#array-splat) <a id="array-splat"></a>
e.g.: given a sample file of
```text
b:
e:
- name: fred
value: 3
- name: sam
value: 4
```
then
```text
yq r sample.yaml 'b.e[*].name'
```
will output:
```text
- fred
- sam
```
Note that the path is in quotes to avoid the square brackets being interpreted by your shell.
### Keys with dots[¶](read.md#keys-with-dots) <a id="keys-with-dots"></a>
When specifying a key that has a dot use key lookup indicator.
```text
b:
foo.bar: 7
```
```text
yaml r sample.yaml 'b[foo.bar]'
```
```text
yaml w sample.yaml 'b[foo.bar]' 9
```
Any valid yaml key can be specified as part of a key lookup.
Note that the path is in quotes to avoid the square brackets being interpreted by your shell.
### Keys \(and values\) with leading dashes[¶](read.md#keys-and-values-with-leading-dashes) <a id="keys-and-values-with-leading-dashes"></a>
If a key or value has leading dashes, yq won't know that you are passing a value as opposed to a flag \(and you will get a 'bad flag syntax' error\).
To fix that, you will need to tell it to stop processing flags by adding '--' after the last flag like so:
```text
yq n -t -- --key --value
```
Will result in
``` --key: --value``

View File

@@ -1,5 +1,5 @@
name: yq name: yq
version: '3.3.1' version: '3.3.2'
summary: A lightweight and portable command-line YAML processor summary: A lightweight and portable command-line YAML processor
description: | description: |
The aim of the project is to be the jq or sed of yaml files. The aim of the project is to be the jq or sed of yaml files.

349
write-update.md Normal file
View File

@@ -0,0 +1,349 @@
# Write
```text
yq w <yaml_file> <path> <new value>
```
### To Stdout[¶](write-update.md#to-stdout) <a id="to-stdout"></a>
Given a sample.yaml file of:
```text
b:
c: 2
```
then
```text
yq w sample.yaml b.c cat
```
will output:
```text
b:
c: cat
```
### From STDIN[¶](write-update.md#from-stdin) <a id="from-stdin"></a>
```text
cat sample.yaml | yq w - b.c blah
```
### Adding new fields[¶](write-update.md#adding-new-fields) <a id="adding-new-fields"></a>
Any missing fields in the path will be created on the fly.
Given a sample.yaml file of:
```text
b:
c: 2
```
then
```text
yq w sample.yaml b.d[+] "new thing"
```
will output:
```text
b:
c: cat
d:
- new thing
```
### Splat[¶](write-update.md#splat) <a id="splat"></a>
Given a sample.yaml file of:
```text
---
bob:
item1:
cats: bananas
item2:
cats: apples
thing:
cats: oranges
```
then
```text
yq w sample.yaml bob.*.cats meow
```
will output:
```text
---
bob:
item1:
cats: meow
item2:
cats: meow
thing:
cats: meow
```
### Prefix Splat[¶](write-update.md#prefix-splat) <a id="prefix-splat"></a>
Given a sample.yaml file of:
```text
---
bob:
item1:
cats: bananas
item2:
cats: apples
thing:
cats: oranges
```
then
```text
yq w sample.yaml bob.item*.cats meow
```
will output:
```text
---
bob:
item1:
cats: meow
item2:
cats: meow
thing:
cats: oranges
```
### Array Splat[¶](write-update.md#array-splat) <a id="array-splat"></a>
Given a sample.yaml file of:
```text
---
bob:
- cats: bananas
- cats: apples
- cats: oranges
```
then
```text
yq w sample.yaml bob[*].cats meow
```
will output:
```text
---
bob:
- cats: meow
- cats: meow
- cats: meow
```
### Appending value to an array field[¶](write-update.md#appending-value-to-an-array-field) <a id="appending-value-to-an-array-field"></a>
Given a sample.yaml file of:
```text
b:
c: 2
d:
- new thing
- foo thing
```
then
```text
yq w sample.yaml "b.d[+]" "bar thing"
```
will output:
```text
b:
c: cat
d:
- new thing
- foo thing
- bar thing
```
Note that the path is in quotes to avoid the square brackets being interpreted by your shell.
### Multiple Documents - update a single document[¶](write-update.md#multiple-documents-update-a-single-document) <a id="multiple-documents-update-a-single-document"></a>
Given a sample.yaml file of:
```text
something: else
---
b:
c: 2
```
then
```text
yq w -d1 sample.yaml b.c 5
```
will output:
```text
something: else
---
b:
c: 5
```
### Multiple Documents - update all documents[¶](write-update.md#multiple-documents-update-all-documents) <a id="multiple-documents-update-all-documents"></a>
Given a sample.yaml file of:
```text
something: else
---
b:
c: 2
```
then
```text
yq w -d'*' sample.yaml b.c 5
```
will output:
```text
something: else
b:
c: 5
---
b:
c: 5
```
Note that '\*' is in quotes to avoid being interpreted by your shell.
### Updating files in-place[¶](write-update.md#updating-files-in-place) <a id="updating-files-in-place"></a>
Given a sample.yaml file of:
```text
b:
c: 2
```
then
```text
yq w -i sample.yaml b.c cat
```
will update the sample.yaml file so that the value of 'c' is cat.
### Updating multiple values with a script[¶](write-update.md#updating-multiple-values-with-a-script) <a id="updating-multiple-values-with-a-script"></a>
Given a sample.yaml file of:
```text
b:
c: 2
e:
- name: Billy Bob
```
and a script update\_instructions.yaml of:
```text
b.c: 3
b.e[+].name: Howdy Partner
```
then
```text
yq w -s update_instructions.yaml sample.yaml
```
will output:
```text
b:
c: 3
e:
- name: Howdy Partner
```
And, of course, you can pipe the instructions in using '-':
```text
cat update_instructions.yaml | yq w -s - sample.yaml
```
### Values starting with a hyphen \(or dash\)[¶](write-update.md#values-starting-with-a-hyphen-or-dash) <a id="values-starting-with-a-hyphen-or-dash"></a>
The flag terminator needs to be used to stop the app from attempting to parse the subsequent arguments as flags:
```text
yq w -- my.path -3
```
will output
```text
my:
path: -3
```
### Keys with dots[¶](write-update.md#keys-with-dots) <a id="keys-with-dots"></a>
When specifying a key that has a dot use key lookup indicator.
```text
b:
foo.bar: 7
```
```text
yaml r sample.yaml 'b[foo.bar]'
```
```text
yaml w sample.yaml 'b[foo.bar]' 9
```
Any valid yaml key can be specified as part of a key lookup.
Note that the path is in quotes to avoid the square brackets being interpreted by your shell.
### Keys \(and values\) with leading dashes[¶](write-update.md#keys-and-values-with-leading-dashes) <a id="keys-and-values-with-leading-dashes"></a>
If a key or value has leading dashes, yq won't know that you are passing a value as opposed to a flag \(and you will get a 'bad flag syntax' error\).
To fix that, you will need to tell it to stop processing flags by adding '--' after the last flag like so:
```text
yq n -t -- --key --value
```
Will result in
``` --key: --value``