0
str='-e ENV_PASSWORD="foo" -e ENV_USER="bar-e sd" -e ENV_DB_NAME="mysite_staging" '

I need to retrieve the environment variable name in one variable and its value in another from the above string using a Bash script.

I tried the below code in Python which works in python3 but the same pattern is not working with grep:

File: python_test.py

import re
str='-e ENV_PASSWORD="foo" -e ENV_USER="bar-e sd" -e ENV_DB_NAME="mysite_staging" '
re_pattern='-e\s+(.*?)="(.*?)"'
rec_pattern = re.compile(re_pattern, re.VERBOSE)
res = rec_pattern.findall(str)

for x in res:
  print(f'Name="{x[0]}" Value="{x[1]}"')
--------------
Output:
Name="ENV_PASSWORD" Value="foo"
Name="ENV_USER" Value="bar-e sd"
Name="ENV_DB_NAME" Value="mysite_staging"

File: bash_test.sh

#!/bin/bash
str='-e ENV_PASSWORD="foo" -e ENV_USER="bar -e sd" -e ENV_DB_NAME="mysite_staging" '
re_pattern='-e\s+(.*?)="(.*?)"'

array=( $(grep -oP $re_pattern <<<$str) )

for i in ${array[@]}; do 
    echo $i;
done
Jeetu
  • 87
  • 1
  • 5

2 Answers2

2

Storing these values in a string seems like an antipattern in the first place. See https://mywiki.wooledge.org/BashFAQ/050

Also, notice that Python and grep (even with -P) have distinct regex dialects and facilities.

Assuming that the format of your input is fairly rigid, I would simply use the built-in regex support in Bash.

#!/bin/bash

str='-e ENV_PASSWORD="foo" -e ENV_USER="bar -e sd" -e ENV_DB_NAME="mysite_staging" '

re_pattern='-e[[:space:]]*([^[:space:].=]*)="([^"]*)"'

while [[ $str =~ $re_pattern ]]; do
    echo "variable: ${BASH_REMATCH[1]}"
    echo "value: ${BASH_REMATCH[2]}"
    str=${str#*${BASH_REMATCH[1]}=\"${BASH_REMATCH[2]}\"}
done

The pattern contains two parenthesized groups (other than that, it's just a reformulation of your Perl pattern to traditional ERE regex) where the first captures the variable, and the second captures the value; these capture groups are collected into the Bash built-in array BASH_REMATCH from where we then pull them out.

This feels rather brittle (especially the parameter expansion at the end of the loop) but it works for your test case.

Demo: https://ideone.com/mY4HKI

As an aside, in your original attempt, you want "$(array[@]}" and echo "$i" with double quotes around the values; see also When to wrap quotes around a shell variable?

A better approach entirely would be to store the configuration in a standard machine-readable format like JSON or YAML, and take it from there.

tripleee
  • 175,061
  • 34
  • 275
  • 318
-1

Use -E option instead of -P:

array=( $(grep -oE $re_pattern <<<$str) )

See live demo.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • Their regex contains several constructs which are only supported with `-P`. It's weird that Ideone seems to accept them, but other `grep` implementation would simply fail or throw an error. – tripleee Sep 24 '22 at 09:15
  • Also. the result shows that the match with a space in it is (predictably) broken up into two results. – tripleee Sep 24 '22 at 09:18
  • @tripleee and yet, it works. I deliberately did not refine OP's regex, focusing only on fixing the basic problem of not using the *extended* flag. – Bohemian Sep 24 '22 at 12:06
  • But that's not correct. The `-P` flag is the correct one for a regex with Perl features like `\s` and `.*?` – tripleee Sep 25 '22 at 09:41