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가 정의 되지 않았습니다.오히려, Bash에서 사용,대신 지정:

여러 개의 인접한 반복 기호("+", "*", "?" 및 공백)의 동작은 정의되지 않은 결과를 생성합니다.

불다시스템 이용 regcomp/regexec정규식 일치에 사용됩니다. Apple의 libc는 원하는 동작을 구현하지 못할 수도 있습니다 *?.

Greedy에서 non-greedy 일치 의미를 복구하는 표준 방법은 없지만, 이 경우에는 적어도 일부는 필요하지 않습니다( [_[:alnum:]]*?첫 번째 것과 같습니다). 그렇지 않으면 다른 것과 일치하도록 표현식을 변환하거나 변경해야 합니다.데이터효과를 얻기 전(그리고 아마도 후에).

답변2

별표는 이미 선택적 개수입니다(0개 문자일 수 있으므로). .?

그렇다면 각 괄호가 키나 값을 캡처해도 괜찮을까요? :

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

관련 정보