Iterating over a specific key and specific variable in a YAML file with awk/grep in bash

Viewed 281

I have a YAML file that I need to iterate and return a specific value for a variable, I am unable to use jq so the only available tool I have is bash. The YAML file looks like this:

abc:
  NAME: Bob
  OCCUPATION: Technician
def:
  NAME: Jane
  OCCUPATION: Engineer

YAML keys are known and will be iterated over, but say I want to get key abc OCCUPATION value of TECHNICIAN, through googling I managed to construct an awk statement that gives what I want, but it seems rather convoluted. Is there a more elegant way to write this out?

Current implementation is

> awk 'BEGIN{OFS=""} /^[^ ]/{ f=/^abc:/; next } f{ if (sub(/:$/,"")) abc=$2; else print abc,$1 $2}' test.yml| grep "OCCUPATION:" | cut -d':' -f2
Technician

If I could use jq it would have been much simpler but alas, I am stuck with base bash!

2 Answers

This answer is also a bit convoluted, but I can't think of anything simpler. With GNU sed:

sed -n '/abc/,/^.*OCCUPATION/{s/.*OCCUPATION\(.*\):\ \(.*\)/\2/p}' test.yaml

Explanation: Find the lines between "abc" and "OCCUPATION" (lines 1 to 3) then from the OCCUPATION line, print the second captured group (the value "Technician") and don't print anything else.

This works regardless of the number of abc elements, but if there is no OCCUPATION value for abc, this will print the next persons's OCCUPATION (in this case, "Engineer") without any warning/error.

For BSD sed:

sed -n '/abc/,/^.*OCCUPATION/ s/.*OCCUPATION\(.*\):\ \(.*\)/\2/p' test.yaml

With awk you can try this:

awk -F'[[:blank:]]+' '$1 == "" {if (s == "abc:" && $2 == "OCCUPATION:") print $3; next} {s=$1}' file
Technician

or the two values:

awk -F'[[:blank:]]+' '$1 == "" {if (s ~ /^(abc:|def:)$/ && $2 == "OCCUPATION:") print $3; next} {s=$1}' file
Technician
Engineer
Related