네거티브 패턴 일치 및 매개변수 확장을 사용하여 bash 배열을 필터링하면 예상치 못한 결과가 나타나는 이유는 무엇입니까?

네거티브 패턴 일치 및 매개변수 확장을 사용하여 bash 배열을 필터링하면 예상치 못한 결과가 나타나는 이유는 무엇입니까?

나는 주사위를 굴리기 위해 작은 순수 bash 스크립트를 만들고 있으므로 배열을 조작해야 합니다. 나는 다른 언어에서 수행되는 것과 유사한 작업을 수행하고 싶습니다 filter. 즉, 배열에서 일부 내용을 추출하여 다른 배열에 넣는 것입니다.

다른 작업(예: 인덱스 간 슬라이싱)에 배열을 사용하는 것이 훨씬 쉽기 때문에 값을 bash 배열로 유지하고 싶습니다.

루프를 사용하여 이 작업을 수행 할 수 있지만 for... do... done패턴 일치가 예상대로 작동하지 않는 이유가 궁금합니다.

shopt -s extglob;
dicerolls=(a b lol kek yolo swag ); 
c=(${dicerolls[@]/!(kek)/}); 
declare -p c;
# Expected: declare -a c=([0]="kek")
# Got: declare -a c=([0]="k")

# One can also see it with this example:
dicerolls=(20 15 7 8 9 0 14 5 6 200 144); c=(${dicerolls[@]/!(14)/}); declare -p c;
# Expected: declare -a c=([0]="14")
# Got: declare -a c=([0]="4")

# Oddly, this works for single-character values
dicerolls=(20 15 7 8 9 0 14 5 6 200 144); c=(${dicerolls[@]/!(8)/}); declare -p c;
# Got: declare -a c=([0]="8")

@ikkachu의 더 간단한 예 편집

var="abcd"
echo "${var/!(abcd)/}"
# Result: d
# Expected: abcd

${dicerolls[@]/%!(14)/}패턴에 없는 항목을 올바르게 일치(및 삭제)하는 것처럼 보이지만 패턴에 포함된 항목을 만나면 일치 항목의 마지막(또는 사용된 경우 첫 번째) 문자 만 가져오는 것 같습니다 . 설명서에서 일종의 길이 제한과 관련된 내용이나 일치 항목이 잘리지 않는다는 것을 보장하는 내용을 찾을 수 없습니다.

나는 이것이 이상하다고 생각하며 이 동작에 대한 "수정"은 물론 설명도 찾지 못했습니다.

따라서 질문은 다음과 같습니다. 배열 매개변수 확장 내부의 패턴 일치를 통해 위의 예상 결과를 얻을 수 있는 방법이 있습니까?

답변1

# Expected: declare -a c=([0]="kek")
# Got: declare -a c=([0]="k")

나는 이것을 다음과 같이 단순화할 수 있다고 생각합니다.

$ var="abcd"
$ echo "${var/!(abcd)/}"
d

그리고 나생각하다var="abbbcd"; echo "${var/a+(b)/}"일어나는 일은 prints 와 비슷합니다 cd. 쉘은 a+(b)문자열의 시작 부분에서 시작하여 가장 긴 일치 항목을 찾는 패턴과 일치하는 항목을 찾으려고 시도합니다. abbbcd또는 abbbc일치하지 않지만 abbb일치하고 해당 부분이 제거됩니다.

(또는 시작해서 a하위 패턴과 일치하는 것을 보고 a계속해서 전체 패턴과 일치하는 것을 볼 수도 있지만 일치하지 않기 때문에 ab가장 오래 일치하는 것입니다.)abbabbbabbbcabbb

마찬가지로, 패턴의 경우 !(abcd)전체 abcd문자열아니요일치하지만 하위 문자열은 abc일치합니다. 삭제되었으며 왼쪽 d.

또는 귀하의 경우 kek에는아니요일치 !(kek)하지만 ke일치합니다. 유지하십시오 k.

비슷하게:

$ var="abcd"
$ echo "${var//!(a*)/}"
a

전체 문자열이 abcd일치하지 않고 !(a*)첫 번째 문자로 시작하는 항목도 일치하지 않으므로 a일치자는 두 번째 문자부터 계속 시작합니다. bcd일치 !(a*)하여 삭제되었습니다.

이는 직관적이지 않은 것처럼 보일 수 있지만 문자열의 어느 위치에서든 일치하는 항목이 계산되는 다른 모든 경우와 유사합니다. 예를 들어 문자열의 중간 부분 과 일치하는 b*e문자열의 패턴을 시도해 보세요. 단지 부정적인 패턴의 경우 일치하는 문자열이 크게 다를 수 있습니다.abcdefgbcde

어쨌든, "필터" 기능과 같은 더 나은 데이터 구조 도구를 갖춘 다른 프로그래밍 언어를 사용하는 것이 더 나을 수도 있습니다.

또한 필터링 아이디어에는 다소 유용하지만 c=(${dicerolls[@]/!(kek)/});따옴표가 없는 확장은 배열 요소에 공백이나 와일드카드가 포함된 경우 문제를 일으킬 수 있습니다. 적절한 "필터" 기능에는 그러한 문제가 없습니다.

관련 정보