I am trying to use Mike Farrah's yq utility to build YAML files from within a bash script. Below is an example of the template I'm using:
---
name: <name>
description: <description>
type: <type>
labels: [label]
data:
- value: <value>
operation: <operation>
labelValues: [value]
The labels and labelValues fields are a list of strings. For example:
labels: [string1, string2, ...]
or
labels:
- string1
- string2
- ...
To add some further complexity, the data field is a list of objects, consisting of the value, operation and labelValues fields.
I'm trying to figure out how to build the labels list, using a bash script array of values. Not having much luck. The closest I've gotten is with the following code:
The array:
$ echo ${labels[@]}
project group
The command:
for lbl in ${labels[@]}; do
yq '.labels.[] |= "'$lbl'"' metric-spec-template.yaml
done
This is what I need:
---
name: <name>
description: <description>
type: <type>
labels: [project, group]
data:
- value: <value>
operation: <operation>
labelValues: <labelValues>
This is what I get:
name: <name>
description: <description>
type: <type>
labels: [project]
data:
- value: <value>
operation: <operation>
labelValues: <labelValues>
name: <name>
description: <description>
type: <type>
labels: [group]
data:
- value: <value>
operation: <operation>
labelValues: <labelValues>
The user guide is nicely written, but I can't figure out how to make this work as needed. I haven't even begun to think about how I would build the list of data items.
Are there any comprehensive tutorials on using yq? I haven't been able to find much beyond the main user guide.
Your approach fails because in the
forloop you're callingyqseparately for each item, but such a call never reads as input the results of the previous iteration, so there's nothingyqcould "update". You should save the intermediary document in a shell variable, or save it to a temporary file, or directly update the source file itself (the latter two make use of the--inplace(or-i) flag).Ideally, though, you should move the entire loop into
yq, and provide to it all the data necessary for the iteration at once, so you'd end up with just one call toyqwhich should then also perform better.Unfortunately, you cannot just import a bash array as a YAML array, as
yqimports variables through the environment, and "There isn't really a good way to encode an array variable into the environment" (by Chet Ramey, the current maintainer of bash).Your remaining options would be:
yqas another YAML input comprising a list of strings (Note that this is an ad-hoc improvident hit-or-miss YAML encoding which would likely break if an item contained certain special characters (e.g. line breaks) capable to invalidate the intended encoding.)yq(Note that this still relies on the items not containing whitespace characters, but as you've usedecho ${labels[@]}andfor lbl in ${labels[@]}; doyourself without quoting the variables, it's fair to assume that they don't.)jqinternally for the JSON processing, while the latter is a full rewrite ofjqthat additionally implements a YAML processor. Thus, both can make use ofjq's--argsflag which allows for the provision of strings as arguments on the command line, which can then be accessed using the built-in$ARGSvariable.