Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Ansible regex to parse multi-line .env file

Please note: there are always alternatives to this, but this is more of an interest / challenge – please focus on the question itself, specifically how to parse a .env file with a valid regex in Ansible. I’m very close.

I have a .env file that I’d like to parse into ansible variables within an ansible playbook. I currently have this working with simple key=value pairs, and also ignoring comments and new lines.

This is the regex replace that works:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

map('regex_replace', '([^=]*)=(.*)', '\\1: \\2')

And the .env file it parses.

KEY2=SOME_TEXT
KEY3="SOME_MORE_TEXT"
KEY4='EVEN_MORE_TEXT'

Problem

However, when I have a multi-line variable in this file, such as:

KEY1='{
    "string" = {
        "key" = "value",
        "key" = "value"
    },
    "string" = {
        "key" = "value",
        "key" = "value"
    }
}'

… then the regex still parses it, but it also changes all of the = into : within that string. I want to ignore anything within those single quotes, and I don’t know how to do that.

Here is the full playbook with the regex I have so far:

---
- name: Read .env file
  hosts: "localhost"
  connection: "local"
  tasks:
    - name: Get env file content
      slurp:
        src: ../.env
      register: env_file_content

    - name: Store env vars in playbook values
      set_fact:
        env_vars: "{{ (env_file_content.content | b64decode).split('\n') | map('regex_replace', '^#.*', '') | select | map('regex_replace', '([^=]*)=(.*)', '\\1: \\2') | join('\n') | from_yaml }}"

    - name: Debug output
      debug:
        var: env_vars

and the full .env file:

# IN TOTAL, THE REGEX SHOULD MATCH 4 KEY-VALUE PAIRS FROM THIS FILE.
KEY1='{
    "string" = {
        "key" = "value",
        "key" = "value"
    },
    "string" = {
        "key" = "value",
        "key" = "value"
    }
}'

# DO NOT MATCH ON COMMENTS, EVEN THOSE WITH X=Y in them.

# ALSO IGNORE THIS COMMENT, AND NEW LINES AROUND.

KEY2=SOME_TEXT
KEY3="SOME_MORE_TEXT"
KEY4='EVEN_MORE_TEXT'

What I need

  • The regex needs to yield four variables that can be accessed in Ansible such as env_vars.KEY1.
  • The regex needs to NOT match anything within KEY1 – it needs to be left untouched.
  • It also needs to prefix each key with PREFIX_, which can be done in the regex_replace with 'PREFIX_\\1: \\2', but you’ll note that it prefixes everything within KEY1 because it matches on the contents of that variable, when I want to ignore that.

How can I update what I have so far to parse a multi-line .env file with a Regex (and prefix each var with a string) in ansible so that I can access the four individual variables?

>Solution :

If you want to use a regex, you might use:

^([^"\s=]+)=('{[\s\S]*?\n}'|.*)

In the replacement you can use PREFIX_\\1: \\2

The pattern matches:

  • ^ Start of string
  • ([^"\s=]+) Capture group 1, match 1+ non whitespace chars other than " and =
  • = Match literally
  • ( Capture group 2
    • '{ Match '{
    • [\s\S]*? Match any character including newlines, as few as possible
    • \n}' Match a newline and then }'
    • | Or
    • .* Match the whole line without newlines
  • ) Close group 2

See a regex demo

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading