Bash

bash 正則表達式提取鍵 = 值

  • January 31, 2019

我有一個這種形式的複雜字元串:

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 約定(或者這樣做?)。我在這裡做錯了什麼?

星號已經是一個可選計數(因為它可能是零個字元)。無需添加?

那麼,如果每個括號都擷取一個鍵或一個值,可以嗎?:

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}"

POSIX 沒有*?為 Bash 使用的ERE定義,而是指定

多個相鄰重複符號(“+”、“*”、“?”和間隔)的行為會產生未定義的結果。

Bash使用系統regcomp/regexec進行正則表達式匹配。蘋果的 libc 大概沒有實現你想要的行為*?

沒有標準的方法可以從貪婪中恢復非貪婪匹配語義,儘管在這種情況下,至少其中一些是不必要的([_[:alnum:]]*?例如,第一個)。否則,您需要轉換錶達式以匹配其他內容或提前(可能之後)改變數據以獲得效果。

引用自:https://unix.stackexchange.com/questions/336072