diff --git a/knowledge base/jq.md b/knowledge base/jq.md
index 1387212..a330f1f 100644
--- a/knowledge base/jq.md
+++ b/knowledge base/jq.md
@@ -6,9 +6,22 @@
## TL;DR
+
+ Installation
+
+```sh
+brew install 'jq'
+docker pull 'ghcr.io/jqlang/jq'
+```
+
+
+
+ Usage
+
```sh
# Only list keys.
jq 'keys' 'file.json'
+docker run --rm -i 'ghcr.io/jqlang/jq' 'keys' 'file.json'
# Sort all the keys.
jq --sort-keys '.' 'input.json' > 'output.json'
@@ -20,11 +33,13 @@ jq '.spec.template.spec.containers[]?.env?' 'manifest.kube.json'
# Add elements to lists.
jq '.orchestrators += [{"orchestratorVersion": "1.24.9"}]'
-jq --arg REGION ${AWS_REGION} '.spec.template.spec.containers[]?.env? += [{name: "AWS_REGION", value: $REGION}]' '/tmp/service.kube.json'
+jq --arg 'REGION' "${AWS_REGION}" \
+ '.spec.template.spec.containers[]?.env? += [{name: "AWS_REGION", value: $REGION}]' \
+ '/tmp/service.kube.json'
yq -iy '.resources+=["awx.yaml"]' 'kustomization.yaml'
# Delete keys from objects.
-jq 'del(.items[].spec.clusterIP)' /tmp/service.kube.json
+jq 'del(.items[].spec.clusterIP)' '/tmp/service.kube.json'
jq 'del(.country, .number, .language)' …
# Remember ranges are **exclusive** of the end index.
jq 'del(.[0,1,2])' …
@@ -39,12 +54,14 @@ jq -r 'to_entries[] | "\(.key) \"\(.value)\""' 'file.json'
# Change single values.
# A.K.A. update values.
-jq '.extensionsGallery
- | .serviceUrl |= "https://marketplace.visualstudio.com/_apis/public/gallery"' \
- /usr/lib/code/product.json
-jq --arg NAMESPACE ${NAMESPACE} \
- '.spec.template.spec.containers[]?.env[]? |= {name: .name, value: (if .name == "KUBERNETES_NAMESPACE" then $NAMESPACE else .value end)}' \
- /tmp/service.kube.json
+jq '.extensionsGallery | .serviceUrl |= "https://marketplace.visualstudio.com/_apis/public/gallery"' \
+ '/usr/lib/code/product.json'
+jq --arg 'NAMESPACE' "$NAMESPACE" \
+ '.spec.template.spec.containers[]?.env[]? |= {
+ "name": .name,
+ "value": (if .name == "KUBERNETES_NAMESPACE" then $NAMESPACE else .value end)
+ }' \
+ '/tmp/service.kube.json'
# Change multiple values at once.
jq '.extensionsGallery
@@ -62,26 +79,27 @@ jq '.extensionsGallery + {
jq '.[0] * .[1]' '1.json' '2.json'
# Only show ('select') elements which specific attribute's value is in a list.
-jq '.[]|select(.PrivateIpAddress|IN("172.31.6.209","172.31.6.229"))|.PrivateDnsName'
+jq '.[]|select(.PrivateIpAddress|IN("172.31.6.209","172.31.6.229"))|.PrivateDnsName' '-'
# Add elements from arrays with the same name from other files.
-jq '.rules=([input.rules]|flatten)' starting-rule-set.json ending-rule-set.json
-jq '.rules=([inputs.rules]|flatten)' starting-rule-set.json parts/*.json
+jq '.rules=([input.rules]|flatten)' 'starting-rule-set.json' 'ending-rule-set.json'
+jq '.rules=([inputs.rules]|flatten)' 'starting-rule-set.json' 'parts'/*'.json'
# Put specific keys on top.
-jq '.objects = [(.objects[] as $in | {type,name,id} + $in)]' prod/dataPipeline_deviceLocationConversion_prod.json
+jq '.objects = [(.objects[] as $in | {type,name,id} + $in)]' 'prod/dataPipeline_deviceLocationConversion_prod.json'
# Convert Enpass' JSON export to a YAML file
-jq '.items[] | {title, fields} | .title + ":", (.fields[] | select(.value != "") | " " + .label + ": " + .value)' test.json -cr
+jq '.items[] | {title, fields} | .title + ":", (.fields[] | select(.value != "") | " " + .label + ": " + .value)' \
+ 'test.json' -cr
# Refactor an AWS DataPipeline definition.
-jq --sort-keys '.' datapipeline.json > /tmp/sorted.json \
+jq --sort-keys '.' datapipeline.json > '/tmp/sorted.json' \
&& jq '.objects = [(.objects[] as $in | {type,name,id} + $in | with_entries(select(.value != null)))]' \
- /tmp/sorted.json > /tmp/reordered.json \
-&& mv /tmp/reordered.json datapipeline.json
+ '/tmp/sorted.json' > '/tmp/reordered.json' \
+&& mv '/tmp/reordered.json' 'datapipeline.json'
# Extract the value of elements with specific keys.
-kubectl get pods -o yaml \
+kubectl get pods -o 'yaml' \
| yq -y '
.items[]
| select(.metadata.name | test("^runner-.*"))
@@ -91,21 +109,23 @@ kubectl get pods -o yaml \
# Recursively find all the properties whose key is 'errors' whether it exists or not.
# '..' unrolls the object, '?' checks for the value or returns null, and 'select(.)' is like a filter on truthy values.
-jq '[.. | .errors?[0] | select(.) ]' /tmp/helm.template.out.json
+jq '[.. | .errors?[0] | select(.) ]' '/tmp/helm.template.out.json'
# Find all images in a helm chart explicitly or implicitly using the tag 'latest'.
-helm template chartName \
+helm template 'chartName' \
| yq -r '
..
| .image?
| select(.)
| select(.|test(".*:.*")|not), select(.|test(".*:$")), select(.|test(".*:latest"))' \
- -
+ '-'
# Check that the 'backend.url key' in a 'Pulumi.yaml' file is not 'file://' and fail otherwise.
yq -e '(.backend.url|test("^file://")?)|not' 'Pulumi.yaml'
```
+
+
## Further readings
- [JQ recipes]
@@ -123,10 +143,10 @@ yq -e '(.backend.url|test("^file://")?)|not' 'Pulumi.yaml'
- [jq: select where .attribute in list]
-
[change multiple values at once]: https://stackoverflow.com/questions/47355901/jq-change-multiple-values#47357956
[deleting multiple keys at once with jq]: https://stackoverflow.com/questions/36227245/deleting-multiple-keys-at-once-with-jq