elle.delle
elle.delle

Reputation: 328

Extracting variable in YAML from a shell script

I have a YAML file composed of the following:

acceleration_matrix:
  # 1ere row: x
  - [20, 0, 0, 15, 15]
  # 2eme row: y
  - [0, 15, 0, 0, 0]
  # 3eme row: z
  - [0, 0, 30, 15, -15]
  # 4eme row: repere de l'acceleration
  - [0, 0, 0, 0, 0]
  # 5eme row: loadcase_id
  - [1, 2, 3, 4, 5]

I want to extract the last value of the last row (in this case, 5) unsing a shell script. Using this article, I coded:

#!/bin/bash

function parse_yaml {
   local prefix=$2
   local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
   sed -ne "s|^\($s\):|\1|" \
        -e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p" \
        -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p"  $1 |
   awk -F$fs '{
      indent = length($1)/2;
      vname[indent] = $2;
      for (i in vname) {if (i > indent) {delete vname[i]}}
      if (length($3) > 0) {
         vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
         printf("%s%s%s=\"%s\"\n", "'$prefix'",vn, $2, $3);
      }
   }'
}

parse_yaml nastran_acceleration_matrix.yml

echo $acceleration_matrix

But as I am a newbie in shell, I can't find how to extract the values. What I would want is simply something like :

set number_load_case = ### acceleration_matrix[-1,-1] ### (I'm more used to coding in python thus the -1 aka last row/column)

Could anybody help me out?

Thanks in advance!

Upvotes: 2

Views: 2938

Answers (3)

Vanshika
Vanshika

Reputation: 45

Install shyaml

 $ pip install shyaml      ## installation

conda env create -f environment.yml -n cat test.yaml | shyaml get-value conda_env_name

You can try above command after installing shyaml.

If this won't work for you, then you can try 'jq' and 'yq' in bash script which will parse your yaml to json and then you can read the values from JSON, after which you can run your command from bash itself.

Upvotes: 2

markp-fuso
markp-fuso

Reputation: 34024

One awk idea based solely on OP's sample input:

$ awk -F'[] ]' '{lastid=$(NF-1)} END {print lastid}' test.yaml
5

Where:

  • -F'[] ]' - set input field delimiter as <space> or ]
  • lastid=$(NF-1) - keep track of next to last field
  • END {print lastid} - print the last 'next to last field' we saved
  • net result: scan entire file, saving next to last field as we progress, and at the end of the file we print/output the last 'next to last' field we captured

To store in a bash variable:

$ number_load_case=$(awk -F'[] ]' '{lastid=$(NF-1)} END {print lastid}' test.yaml)
$ echo "${number_load_case}"
5

NOTES:

  • this will obviously generate an incorrect result if the input is not formatted exactly as in OPs sample (eg, if last line is blank then awk will fail with error: fatal: attempt to access field -1)
  • as already mentioned something like yq would be better suited to this problem, especially if formatting is not as 'pretty' as in OP's sample
  • for less 'pretty' formatting, and the inability to use something like yq, a more robust parser could be written (eg, in awk)

Upvotes: 1

Benjamin W.
Benjamin W.

Reputation: 52112

I'd recommend using a proper parser such as yq. Your task (last value of last element of acceleration_matrix) then becomes as simple as

yq eval '.acceleration_matrix[-1][-1]' nastran_acceleration_matrix.yml

Upvotes: 1

Related Questions