Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I parse a YAML file from a Linux shell script?

Tags:

shell

yaml

I wish to provide a structured configuration file which is as easy as possible for a non-technical user to edit (unfortunately it has to be a file) and so I wanted to use YAML. I can't find any way of parsing this from a Unix shell script however.

like image 757
yazz.com Avatar asked Feb 16 '11 09:02

yazz.com


People also ask

What is YAML parser?

YAML (Yet Another Markup Language) is a format for serializing data in a text file. It is similar to other textual data formats such as JSON and XML. YAML is widely used for storing configuration data for software applications, build systems, and deployment platforms.

Does jq work with YAML?

a lightweight and portable command-line YAML processor. yq uses jq like syntax but works with yaml files as well as json.


1 Answers

Here is a bash-only parser that leverages sed and awk to parse simple yaml files:

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);       }    }' } 

It understands files such as:

## global definitions global:   debug: yes   verbose: no   debugging:     detailed: no     header: "debugging started"  ## output output:    file: "yes" 

Which, when parsed using:

parse_yaml sample.yml 

will output:

global_debug="yes" global_verbose="no" global_debugging_detailed="no" global_debugging_header="debugging started" output_file="yes" 

it also understands yaml files, generated by ruby which may include ruby symbols, like:

--- :global:   :debug: 'yes'   :verbose: 'no'   :debugging:     :detailed: 'no'     :header: debugging started   :output: 'yes' 

and will output the same as in the previous example.

typical use within a script is:

eval $(parse_yaml sample.yml) 

parse_yaml accepts a prefix argument so that imported settings all have a common prefix (which will reduce the risk of namespace collisions).

parse_yaml sample.yml "CONF_" 

yields:

CONF_global_debug="yes" CONF_global_verbose="no" CONF_global_debugging_detailed="no" CONF_global_debugging_header="debugging started" CONF_output_file="yes" 

Note that previous settings in a file can be referred to by later settings:

## global definitions global:   debug: yes   verbose: no   debugging:     detailed: no     header: "debugging started"  ## output output:    debug: $global_debug 

Another nice usage is to first parse a defaults file and then the user settings, which works since the latter settings overrides the first ones:

eval $(parse_yaml defaults.yml) eval $(parse_yaml project.yml) 
like image 137
Stefan Farestam Avatar answered Sep 19 '22 08:09

Stefan Farestam