mirror of
https://github.com/mikefarah/yq.git
synced 2025-01-23 14:16:10 +00:00
Added pipe and length docs, fix pipe precedence
This commit is contained in:
parent
da027f69d7
commit
c9dbf04da3
19
README.md
19
README.md
@ -25,16 +25,16 @@ 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 r - 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 w - 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 w - 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
|
||||
```
|
||||
@ -48,7 +48,7 @@ wget https://github.com/mikefarah/yq/releases/download/{VERSION}/{BINARY} -O /us
|
||||
chmod +x /usr/bin/yq
|
||||
```
|
||||
|
||||
For instance, VERSION=3.4.0 and BINARY=yq_linux_amd64
|
||||
For instance, VERSION=4.0.0 and BINARY=yq_linux_amd64
|
||||
|
||||
|
||||
### Run with Docker
|
||||
@ -56,7 +56,7 @@ For instance, VERSION=3.4.0 and BINARY=yq_linux_amd64
|
||||
#### Oneshot use:
|
||||
|
||||
```bash
|
||||
docker run --rm -v "${PWD}":/workdir mikefarah/yq yq [flags] <command> FILE...
|
||||
docker run --rm -v "${PWD}":/workdir mikefarah/yq <command> [flags] [expression ]FILE...
|
||||
```
|
||||
|
||||
#### Run commands interactively:
|
||||
@ -69,13 +69,13 @@ It can be useful to have a bash function to avoid typing the whole docker comman
|
||||
|
||||
```bash
|
||||
yq() {
|
||||
docker run --rm -i -v "${PWD}":/workdir mikefarah/yq yq "$@"
|
||||
docker run --rm -i -v "${PWD}":/workdir mikefarah/yq "$@"
|
||||
}
|
||||
```
|
||||
|
||||
### Go Get:
|
||||
```
|
||||
GO111MODULE=on go get github.com/mikefarah/yq/v3
|
||||
GO111MODULE=on go get github.com/mikefarah/yq/v4
|
||||
```
|
||||
|
||||
## Community Supported Installation methods
|
||||
@ -108,9 +108,8 @@ Supported by @rmescandon (https://launchpad.net/~rmescandon/+archive/ubuntu/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)
|
||||
- Colorized yaml output
|
||||
- [Deep read a yaml file with a given path expression](https://mikefarah.gitbook.io/yq/v/v4.x/traverse)
|
||||
- [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
|
||||
|
4
go.mod
4
go.mod
@ -1,18 +1,14 @@
|
||||
module github.com/mikefarah/yq/v4
|
||||
|
||||
require (
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 // indirect
|
||||
github.com/elliotchance/orderedmap v1.3.0
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/goccy/go-yaml v1.8.1
|
||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
||||
github.com/mattn/go-colorable v0.1.7 // indirect
|
||||
github.com/spf13/cobra v1.1.1
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/timtadh/data-structures v0.5.3 // indirect
|
||||
github.com/timtadh/lexmachine v0.2.2
|
||||
github.com/ugorji/go v1.1.4 // indirect
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 // indirect
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
||||
|
13
go.sum
13
go.sum
@ -17,7 +17,6 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
@ -27,9 +26,7 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
@ -76,7 +73,6 @@ github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm4
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
@ -120,7 +116,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
@ -177,8 +172,6 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
|
||||
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
@ -186,7 +179,6 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@ -200,9 +192,7 @@ github.com/timtadh/data-structures v0.5.3/go.mod h1:9R4XODhJ8JdWFEI8P/HJKqxuJctf
|
||||
github.com/timtadh/lexmachine v0.2.2 h1:g55RnjdYazm5wnKv59pwFcBJHOyvTPfDEoz21s4PHmY=
|
||||
github.com/timtadh/lexmachine v0.2.2/go.mod h1:GBJvD5OAfRn/gnp92zb9KTgHLB7akKyxmVivoYCcjQI=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
@ -244,7 +234,6 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@ -325,7 +314,6 @@ google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBr
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
@ -344,6 +332,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -8,7 +8,7 @@ This will do a similar thing to the plain form, however, the RHS expression is r
|
||||
## Create yaml file
|
||||
Running
|
||||
```bash
|
||||
yq eval --null-input '(.a.b = "cat") | (.x = "frog")'
|
||||
yq eval --null-input '.a.b = "cat" | .x = "frog"'
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@ -112,7 +112,7 @@ a:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.[] | select(. == "apple") |= "frog"' sample.yml
|
||||
yq eval '(.a.[] | select(. == "apple")) = "frog"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@ -130,7 +130,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | select(. == "*andy") |= "bogs"' sample.yml
|
||||
yq eval '(.[] | select(. == "*andy")) = "bogs"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
54
pkg/yqlib/doc/Length.md
Normal file
54
pkg/yqlib/doc/Length.md
Normal file
@ -0,0 +1,54 @@
|
||||
Returns the lengths of the nodes. Length is defined according to the type of the node.
|
||||
|
||||
## String length
|
||||
returns length of string
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | length' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
3
|
||||
```
|
||||
|
||||
## Map length
|
||||
returns number of entries
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cat
|
||||
c: dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'length' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
2
|
||||
```
|
||||
|
||||
## Array length
|
||||
returns number of elements
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- 2
|
||||
- 4
|
||||
- 6
|
||||
- 8
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval 'length' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
4
|
||||
```
|
||||
|
35
pkg/yqlib/doc/Pipe.md
Normal file
35
pkg/yqlib/doc/Pipe.md
Normal file
@ -0,0 +1,35 @@
|
||||
Pipe the results of an expression into another. Like the bash operator.
|
||||
|
||||
## Simple Pipe
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
b: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a | .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cat
|
||||
```
|
||||
|
||||
## Multiple updates
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cow
|
||||
b: sheep
|
||||
c: same
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = "cat" | .b = "dog"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: cat
|
||||
b: dog
|
||||
c: same
|
||||
```
|
||||
|
1
pkg/yqlib/doc/headers/Length.md
Normal file
1
pkg/yqlib/doc/headers/Length.md
Normal file
@ -0,0 +1 @@
|
||||
Returns the lengths of the nodes. Length is defined according to the type of the node.
|
1
pkg/yqlib/doc/headers/Pipe.md
Normal file
1
pkg/yqlib/doc/headers/Pipe.md
Normal file
@ -0,0 +1 @@
|
||||
Pipe the results of an expression into another. Like the bash operator.
|
@ -29,6 +29,8 @@ var And = &OperationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: AndOp
|
||||
|
||||
var Union = &OperationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: UnionOperator}
|
||||
|
||||
var Pipe = &OperationType{Type: "PIPE", NumArgs: 2, Precedence: 30, Handler: PipeOperator}
|
||||
|
||||
var Assign = &OperationType{Type: "ASSIGN", NumArgs: 2, Precedence: 40, Handler: AssignUpdateOperator}
|
||||
var AddAssign = &OperationType{Type: "ADD_ASSIGN", NumArgs: 2, Precedence: 40, Handler: AddAssignOperator}
|
||||
|
||||
@ -42,7 +44,8 @@ var Add = &OperationType{Type: "ADD", NumArgs: 2, Precedence: 45, Handler: AddOp
|
||||
|
||||
var Equals = &OperationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: EqualsOperator}
|
||||
var CreateMap = &OperationType{Type: "CREATE_MAP", NumArgs: 2, Precedence: 40, Handler: CreateMapOperator}
|
||||
var Pipe = &OperationType{Type: "PIPE", NumArgs: 2, Precedence: 45, Handler: PipeOperator}
|
||||
|
||||
var ShortPipe = &OperationType{Type: "PIPE", NumArgs: 2, Precedence: 45, Handler: PipeOperator}
|
||||
|
||||
var Length = &OperationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: LengthOperator}
|
||||
var Collect = &OperationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: CollectOperator}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
var assignOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
description: "Create yaml file",
|
||||
expression: `(.a.b = "cat") | (.x = "frog")`,
|
||||
expression: `.a.b = "cat" | .x = "frog"`,
|
||||
expected: []string{
|
||||
"D0, P[], ()::a:\n b: cat\nx: frog\n",
|
||||
},
|
||||
@ -80,7 +80,7 @@ var assignOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
description: "Update selected results",
|
||||
document: `{a: {b: apple, c: cactus}}`,
|
||||
expression: `.a.[] | select(. == "apple") |= "frog"`,
|
||||
expression: `(.a.[] | select(. == "apple")) = "frog"`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: {b: frog, c: cactus}}\n",
|
||||
},
|
||||
@ -88,7 +88,7 @@ var assignOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
description: "Update array values",
|
||||
document: `[candy, apple, sandy]`,
|
||||
expression: `.[] | select(. == "*andy") |= "bogs"`,
|
||||
expression: `(.[] | select(. == "*andy")) = "bogs"`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::[bogs, apple, bogs]\n",
|
||||
},
|
||||
|
35
pkg/yqlib/operator_length.go
Normal file
35
pkg/yqlib/operator_length.go
Normal file
@ -0,0 +1,35 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func LengthOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- lengthOperation")
|
||||
var results = list.New()
|
||||
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
targetNode := UnwrapDoc(candidate.Node)
|
||||
var length int
|
||||
switch targetNode.Kind {
|
||||
case yaml.ScalarNode:
|
||||
length = len(targetNode.Value)
|
||||
case yaml.MappingNode:
|
||||
length = len(targetNode.Content) / 2
|
||||
case yaml.SequenceNode:
|
||||
length = len(targetNode.Content)
|
||||
default:
|
||||
length = 0
|
||||
}
|
||||
|
||||
node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", length), Tag: "!!int"}
|
||||
lengthCand := &CandidateNode{Node: node, Document: candidate.Document, Path: candidate.Path}
|
||||
results.PushBack(lengthCand)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
42
pkg/yqlib/operator_length_test.go
Normal file
42
pkg/yqlib/operator_length_test.go
Normal file
@ -0,0 +1,42 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var lengthOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
description: "String length",
|
||||
subdescription: "returns length of string",
|
||||
document: `{a: cat}`,
|
||||
expression: `.a | length`,
|
||||
expected: []string{
|
||||
"D0, P[a], (!!int)::3\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Map length",
|
||||
subdescription: "returns number of entries",
|
||||
document: `{a: cat, c: dog}`,
|
||||
expression: `length`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!int)::2\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Array length",
|
||||
subdescription: "returns number of elements",
|
||||
document: `[2,4,6,8]`,
|
||||
expression: `length`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!int)::4\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestLengthOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range lengthOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentScenarios(t, "Length", lengthOperatorScenarios)
|
||||
}
|
@ -111,7 +111,7 @@ func createTraversalTree(path []interface{}) *PathTreeNode {
|
||||
return &PathTreeNode{Operation: &Operation{OperationType: TraversePath, Value: path[0], StringValue: fmt.Sprintf("%v", path[0])}}
|
||||
}
|
||||
return &PathTreeNode{
|
||||
Operation: &Operation{OperationType: Pipe},
|
||||
Operation: &Operation{OperationType: ShortPipe},
|
||||
Lhs: createTraversalTree(path[0:1]),
|
||||
Rhs: createTraversalTree(path[1:])}
|
||||
|
||||
|
11
pkg/yqlib/operator_pipe.go
Normal file
11
pkg/yqlib/operator_pipe.go
Normal file
@ -0,0 +1,11 @@
|
||||
package yqlib
|
||||
|
||||
import "container/list"
|
||||
|
||||
func PipeOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.GetMatchingNodes(lhs, pathNode.Rhs)
|
||||
}
|
31
pkg/yqlib/operator_pipe_test.go
Normal file
31
pkg/yqlib/operator_pipe_test.go
Normal file
@ -0,0 +1,31 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var pipeOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
description: "Simple Pipe",
|
||||
document: `{a: {b: cat}}`,
|
||||
expression: `.a | .b`,
|
||||
expected: []string{
|
||||
"D0, P[a b], (!!str)::cat\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Multiple updates",
|
||||
document: `{a: cow, b: sheep, c: same}`,
|
||||
expression: `.a = "cat" | .b = "dog"`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: cat, b: dog, c: same}\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestPipeOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range pipeOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentScenarios(t, "Pipe", pipeOperatorScenarios)
|
||||
}
|
@ -2,7 +2,6 @@ package yqlib
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
@ -20,14 +19,6 @@ func EmptyOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *Pat
|
||||
return list.New(), nil
|
||||
}
|
||||
|
||||
func PipeOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.GetMatchingNodes(lhs, pathNode.Rhs)
|
||||
}
|
||||
|
||||
func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode {
|
||||
valString := "true"
|
||||
if !value {
|
||||
@ -42,29 +33,3 @@ func nodeToMap(candidate *CandidateNode) *list.List {
|
||||
elMap.PushBack(candidate)
|
||||
return elMap
|
||||
}
|
||||
|
||||
func LengthOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
log.Debugf("-- lengthOperation")
|
||||
var results = list.New()
|
||||
|
||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
var length int
|
||||
switch candidate.Node.Kind {
|
||||
case yaml.ScalarNode:
|
||||
length = len(candidate.Node.Value)
|
||||
case yaml.MappingNode:
|
||||
length = len(candidate.Node.Content) / 2
|
||||
case yaml.SequenceNode:
|
||||
length = len(candidate.Node.Content)
|
||||
default:
|
||||
length = 0
|
||||
}
|
||||
|
||||
node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", length), Tag: "!!int"}
|
||||
lengthCand := &CandidateNode{Node: node, Document: candidate.Document, Path: candidate.Path}
|
||||
results.PushBack(lengthCand)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*Token) ([]*Operation, er
|
||||
// now we should have [] as the last element on the opStack, get rid of it
|
||||
opStack = opStack[0 : len(opStack)-1]
|
||||
//and append a collect to the opStack
|
||||
opStack = append(opStack, &Token{TokenType: OperationToken, Operation: &Operation{OperationType: Pipe}})
|
||||
opStack = append(opStack, &Token{TokenType: OperationToken, Operation: &Operation{OperationType: ShortPipe}})
|
||||
opStack = append(opStack, &Token{TokenType: OperationToken, Operation: &Operation{OperationType: collectOperator}})
|
||||
case CloseBracket:
|
||||
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != OpenBracket {
|
||||
|
@ -318,7 +318,7 @@ func (p *pathTokeniser) Tokenise(path string) ([]*Token, error) {
|
||||
if index != len(tokens)-1 && token.CheckForPostTraverse &&
|
||||
tokens[index+1].TokenType == OperationToken &&
|
||||
tokens[index+1].Operation.OperationType == TraversePath {
|
||||
op := &Operation{OperationType: Pipe, Value: "PIPE"}
|
||||
op := &Operation{OperationType: ShortPipe, Value: "PIPE"}
|
||||
postProcessedTokens = append(postProcessedTokens, &Token{TokenType: OperationToken, Operation: op})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user