bash正则表达式提取键=值

bash正则表达式提取键=值

我有一个这种形式的复杂字符串:

inp="key1 =   what' ever the value key2 = the value Nb.2   key3= \"last value\""

我需要获取与其第一个值关联的第一个键。我想使用 bash 正则表达式来提取键、值以及字符串中剩余的内容:

rkeyval="[[:space:]]*([_[:alnum:]]*?)[[:space:]]*=[[:space:]]*((.*?)[[:space:]]+([_[:alnum:]]+?[[:space:]]*=[[:space:]]*.*))"

if [[ $inp =~ $rkeyval ]]; then

  key=${BASH_REMATCH[1]}
  val=${BASH_REMATCH[3]}
  left=${BASH_REMATCH[4]}

  for i in $(seq 0 $(( ${#BASH_REMATCH[*]}-1 ))); do  
    echo -e "$i: \"${BASH_REMATCH[$i]}\""; 
  done; 
else
  echo "no match"
fi

这是行不通的。在我的装有 Bash 4.4 的 Mac 上,没有匹配项:

no match

在我的 Red Hat Linux 上,我得到以下输出:

0: "key1 =   what' ever the value key2 = the value Nb.2   key3= "last value""
1: "key1"
2: "what' ever the value key2 = the value Nb.2   key3= "last value""
3: "what' ever the value key2 = the value Nb.2  "
4: "key3= "last value""

我期望以下输出:

0: "key1 =   what' ever the value key2 = the value Nb.2   key3= "last value""
1: "key1"
2: "what' ever the value key2 = the value Nb.2   key3= "last value""
3: "what' ever the value"
4: "key3= "last value""

换句话说,键是第二个匹配组,值是第三个匹配组。

这个表达式适用于在线PHP 正则表达式测试器

我希望它可以在任何具有 Bash 更新版本的 Unix 机器上运行。

我不知道为什么这不起作用,以及为什么结果从一个平台到另一个平台不同,即使我的正则表达式尊重 Posix 约定(或者确实如此?)。我在这里做错了什么?

答案1

POSIX 没有*?定义ERE,Bash 使用的,相反指定

多个相邻重复符号(“+”、“*”、“?”和间隔)的行为会产生未定义的结果。

重击使用系统regcomp/regexec用于正则表达式匹配。 Apple 的 libc 可能没有实现您想要的行为*?

没有标准方法可以从贪婪中恢复非贪婪匹配语义,尽管在这种情况下至少其中一些是不必要的([_[:alnum:]]*?例如第一个)。否则,您需要转换表达式以匹配其他内容或改变数据提前(也可能是之后)以获得效果。

答案2

星号已经是一个可选计数(因为它可以是零个字符)。无需添加 an ?

那么,如果每个括号都捕获一个键或一个值可以吗?:

s='[[:space:]]*'        # spaces
n='[_[:alnum:]]+'       # a valid name (limited by spaces)
e="${s}=${s}"           # an equal sign (=).

rkeyval="${s}(${n})${e}([^=]*) (${n})${e}([^=]*) (${n})${e}(.*)"
#            1^^^^^    2^^^^^^ 3^^^^^    4^^^^^^ 5^^^^^    6^^^
echo "$rkeyval"

这将捕获如下:

if [[ $inp =~ $rkeyval ]]; then

    i=0
    while ((i<${#BASH_REMATCH[@]})); do
        printf '%s: "%s"\n' "$((i))" "${BASH_REMATCH[i++]}";
    done
else
    echo "no match"
fi

印刷:

0: "key1 =   what' ever the value key2 = the value Nb.2   key3= "last value""
1: "key1"
2: "what' ever the value"
3: "key2"
4: "the value Nb.2  "
5: "key3"
6: ""last value""

你想要的值(如果我正确理解你的代码)可以近似为(编辑以获得完美匹配):

key="${BASH_REMATCH[1]}"
val="${BASH_REMATCH[@]:2:3}"
left="${BASH_REMATCH[@]:5:2}"

相关内容