다음 형식의 복잡한 문자열이 있습니다.
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}"