Dears,
I need your support with this below regex I've been at it for the last 5 hours and could not figure it out
define\(\s*[\'"]DB_HOST[\'"]\s*,\s*[\'"]([^\'"]+)[\'"]\)
The task I have is simple I need a regex to extract WordPress database information and I will be using it in an Ansible playbook
/\*\* The host of the database for WordPress \*/
define( 'DB_HOST', 'database_host_here' );
the above is the format
I tried more than regex with the help of ChatGPT and other GenAI tools but every output fails due to a regex escape issue
this is my current playbook
---
- name: Update wp-config.php with new template
hosts: localhost
vars_prompt:
- name: username
prompt: "Enter the username"
private: false
vars:
wp_config_filename: "wp-config.php"
enable_debug: false
multi_site: false
search_paths:
- "/home/{{ username }}/public_html/public"
tasks:
- name: Find wp-config.php files
ansible.builtin.find:
paths: "{{ search_paths }}"
patterns: "{{ wp_config_filename }}"
register: wp_config_files
- name: Fail if no wp-config.php files found
ansible.builtin.fail:
msg: "No wp-config.php files found in the provided paths."
when: wp_config_files.matched == 0
- name: Debug wp-config.php files
ansible.builtin.debug:
var: wp_config_files
- name: Read existing wp-config.php for database credentials
ansible.builtin.slurp:
src: "{{ item.path }}"
loop: "{{ wp_config_files.files }}"
loop_control:
loop_var: item
register: wp_config_content
when: wp_config_files.matched > 0
- name: Decode base64 encoded wp-config.php content
ansible.builtin.set_fact:
wp_config_decoded: "{{ wp_config_content.results | map(attribute='content') | map('b64decode') | list }}"
- name: Debug decoded wp-config.php content
ansible.builtin.debug:
var: wp_config_decoded
- name: Set database credentials from existing wp-config.php
ansible.builtin.set_fact:
db_host: "{{ item | regex_search('define\\(\\s*[\'\"]DB_HOST[\'\"]\\s*,\\s*[\'\"]([^\'\"]+)[\'\"]') | default('localhost') }}"
db_name: "{{ item | regex_search('define\\(\\s*[\'\"]DB_NAME[\'\"]\\s*,\\s*[\'\"]([^\'\"]+)[\'\"]') | default('wordpress') }}"
db_user: "{{ item | regex_search('define\\(\\s*[\'\"]DB_USER[\'\"]\\s*,\\s*[\'\"]([^\'\"]+)[\'\"]') | default('root') }}"
db_password: "{{ item | regex_search('define\\(\\s*[\'\"]DB_PASSWORD[\'\"]\\s*,\\s*[\'\"]([^\'\"]+)[\'\"]') | default('password') }}"
loop: "{{ wp_config_decoded }}"
loop_control:
loop_var: item
- name: Debug extracted database credentials
ansible.builtin.debug:
msg: >
DB Name: {{ db_name }},
DB User: {{ db_user }},
DB Password: {{ db_password }},
DB Host: {{ db_host }}
- name: Create a new wp-config.php from template
ansible.builtin.template:
src: "wp-config.php.j2"
dest: "{{ item.path }}"
mode: "0644"
loop: "{{ wp_config_files.files }}"
when: wp_config_files.matched > 0
I have a shared hosting environment with more than one WordPress website and I want to make all the settings are the same so I want to automate the detection of the database information, update the template, and place it in the correct path.
define\(\s*[\'"]DB_HOST[\'"]\s*,\s*[\'"]([^\'"]+)[\'"]\)
It fails with ansible
UPDATE
Thanks to @WiktorStribiżew I was able to figure out the solution to my issue
The new and updated regex value with regex_search for ansible
regex_search('define\\s*\\(\\s*[\\x22\\x27]DB_HOST[\\x22\\x27]\\s*,\\s*[\\x22\\x27]([^\\x22\\x27]+)[\\x22\\x27]\\s*\\)', '\\1') | first
UPDATE 2:
Based on @U880D's answer, if someone faces the same case or wants to implement the same task.
Full Playbook:
---
- name: Update wp-config.php with new template
hosts: all
become: true
tasks:
- name: Find all user directories under /home
ansible.builtin.find:
paths: "{{ search_path }}"
file_type: directory
register: user_dirs
- name: Find all wp-config.php files in user directories
ansible.builtin.find:
paths: "{{ item.path }}/public_html"
patterns: "wp-config.php"
register: wp_config_files
loop: "{{ user_dirs.files }}"
- name: Fail if no wp-config.php files found
ansible.builtin.fail:
msg: "No wp-config.php files found in the provided paths."
when: wp_config_files.matched == 0
- name: Debug wp-config.php files
ansible.builtin.debug:
var: wp_config_files
- name: Read existing wp-config.php for database credentials
ansible.builtin.slurp:
src: "{{ item.path }}"
loop: "{{ wp_config_files.files }}"
register: wp_config_content
when: wp_config_files.matched > 0
- name: Debug wp-config.php content
ansible.builtin.debug:
var: wp_config_content.results
- name: Set database credentials from existing wp-config.php
ansible.builtin.set_fact:
db_host: >-
{{ item.content | b64decode | regex_search('DB_HOST(.+)', '\\1') | regex_search('([A-Za-z])+') }}
db_name: >-
{{ item.content | b64decode | regex_search('DB_NAME(.+)', '\\1') | regex_search('([A-Za-z])+') }}
db_user: >-
{{ item.content | b64decode | regex_search('DB_USER(.+)', '\\1') | regex_search('([A-Za-z])+') }}
db_password: >-
{{ item.content | b64decode | regex_search('DB_PASSWORD(.+)', '\\1') | regex_search('([A-Za-z])+') }}
loop: "{{ wp_config_content.results }}"
loop_control:
loop_var: item
when: item.content is defined
- name: Debug extracted database credentials
ansible.builtin.debug:
msg: >-
DB Name: {{ db_name }},
DB User: {{ db_user }},
DB Password: {{ db_password }},
DB Host: {{ db_host }}
- name: Create a new wp-config.php from template
ansible.builtin.template:
src: "wp-config.php.j2"
dest: "{{ item.path }}"
mode: "0644"
loop: "{{ wp_config_files.files }}"
when: wp_config_files.matched > 0
There is a workaround for adding double and single quotes to your regex pattern if you have trouble understanding how to escape them inside your string literals. This works with most -if not all - NFA regex engines.
You can match "
with \x22
and '
with \x27
escape entity.
So, your pattern will look like
regex_search('define\\(\\s*[\\x22\\x27]DB_HOST[\\x22\\x27]\\s*,\\s*[\\x22\\x27]([^\\x22\\x27]+)[\\x22\\x27]\\s*\\)')
Note that if you need to get the group value from the result, you need to specify it as the second argument to regex_search
:
regex_search('define\\(\\s*[\\x22\\x27]DB_HOST[\\x22\\x27]\\s*,\\s*[\\x22\\x27]([^\\x22\\x27]+)[\\x22\\x27]\\s*\\)', '\\1')
Since you obtain a list as a result of your code execution, and you only need the first item in that list, all you need is to add the | first
after your regex search command.