Saturday, January 18, 2014

Using bash for a simple 'Domain Specific Micro Language'

I had bash scripts to manage some rules (like ACL), and I had it all in a single script, which kept growing with the addition of new rules. At one point a senior colleague of mine, suggested to split/separate them out into separate manageable files. I thought it was time to move the script to Perl, but then I thought, let me give bash one more shot! and I had some fun [after a long time] with bash.

I came up with this simple approach to model the rules, a file with rule and end keywords and all the required data, as key-value pairs within, like:

rule
   object=obj1
   access=any
   action=allow
end
rule
   object=obj2
   access=write,execute
   action=deny
end

And then, a processor script to convert files like these to actual rules (suitable for consumption in our system). The skeleton of the processor script:
do_process() {
 for k in "${!vartbl[@]}"; do
  # use $k and ${vartbl[$k]}
 done
}
declare -A vartbl

split_kp_re='([a-zA-Z0-9_-]+)=(.*)'
rule_id=0
while read i; do
    if [[ $i =~ '# ' ]] ; then continue; fi # skip comments
    case $i in
        'rule')
           rule_id=$(($rule_id + 1))
         ;;
        'end')
           do_process  
           vartbl=()
         ;;
        *)
           [[ $i =~ $split_kp_re ]]
           k=${BASH_REMATCH[1]}
           v=${BASH_REMATCH[2]}
           vartbl["$k"]=$v
         ;;
    esac
done < $infile

Where $infile is the input file (can be read from command line).
As can be seen, the function do_process  which shall process one rule at a time, can use the values from the associative-array vartbl and write it out in any required format, and our files can have comments too! (lines beginning with a #) :-)
Note: bash 4.0 or later required for associative array support.

No comments: