Mike Farah’s yq yaml processor has a a rich set of operators and functions for advanced usage. In this article, I will illustrate how to update a deeply nested element in yaml.
Install yq
Here are the steps for installing the latest yq on Snap enabled systems like Ubuntu/Debian. See the notes at bottom if you need manual installation instead.
sudo snap install yq yq --version
Sample yaml
We will use the following yaml files to illustrate finding and updating the deeply nested ‘tags’ element.
cat <<EOF >company-servers.yaml company: regions: [ 'us-east', 'us-central', 'us-west'] inventory: machineA: region: us-east tags: - linux machineB: region: us-central tags: - windows EOF
Finding and updating deeply nested yaml element
Updating an element like ‘regions’ would be relatively simple because the dotted path is well known as ‘.company.regions’
$ yq '.company.regions = ["americas","europe"]' company-servers.yaml company: regions: [americas, europe] inventory: machineA: region: us-east tags: - linux machineB: region: us-central tags: - windows
However, updating the ‘tags’ element nested deeply in each machine object would be more difficult to express because of the variability of the ‘machine<ID>’ elements. Luckily we can use the double dot “..” notation to find and update any arbitrarily nested “tags” element.
$ yq '(.. | select(has("tags")).tags) = ["coreos","arm64"]' company-servers.yaml company: regions: ['us-east', 'us-central', 'us-west'] inventory: machineA: region: us-east tags: - coreos - arm64 machineB: region: us-central tags: - coreos - arm64
Or if we wanted to append array elements, we could use the “+=” operator
yq '(.. | select(has("tags")).tags) += ["amd64"]' company-servers.yaml
Or if we wanted to update only the machine objects where the region was “us-east”
yq '(.. | select(has("tags") and .region=="us-east").tags) += ["amd64"]' company-servers.yaml
Github project
The examples shown above can be pulled down from my github project.
myproject=https://raw.githubusercontent.com/fabianlee/blogcode wget $myproject/master/yq/update-filesection/company-servers.yaml wget $myproject/master/yq/update-filesection/yq-mikefarah-update-deep-element.sh chmod +x *.sh # run script ./yq-mikefarah-update-deep-element.sh
REFERENCES
stackoverflow, ‘select’ and ‘has’ to update with yq
yq docs, logic without if/then/else
stackoverflow, select in place of ‘if’ statement
yq docs, multiple merge operators: + d ? n c
yq docs, and or boolean operators
yq, filter from array and append to another file
NOTES
Manual download and installation
# essential packages sudo apt get install curl jq wget -y # get latest release version latest_yq_linux=$(curl -sL https://api.github.com/repos/mikefarah/yq/releases/latest | jq -r ".assets[].browser_download_url" | grep linux_amd64.tar.gz) # download, extract, and put binary into PATH wget $latest_yq_linux tar xvfz yq_linux_amd64.tar.gz sudo cp yq_linux_amd64 /usr/local/bin/yq