범위 없는 대괄호 표현식은 bash의 예기치 않은 문자와 일치합니다.

범위 없는 대괄호 표현식은 bash의 예기치 않은 문자와 일치합니다.

저는 Linux에서 bash를 사용하고 있습니다. 다음 if 문에서 성공했지만 실패 코드를 반환하면 안 되나요?

if [[ ■ = [⅕⅖⅗] ]] ; then echo yes ; fi

사각형은 어떤 문자와도 같지 않은데 왜 성공 코드가 나오는지 이해가 되지 않습니다.

내 상자에 이중 괄호를 보관하는 것이 중요합니다.

이 경우 범위를 달성하는 다른 방법이나 다른 제안이 있습니까?

답변1

이는 이러한 문자가 동일한 정렬 순서를 갖고 있기 때문입니다.

너도 눈치챌 거야

sort -u << EOF
EOF

하나의 행만 반환됩니다.

또는:

expr ■ = ⅕

true를 반환합니다(POSIX에서 요구하는 대로).

GNU 시스템과 함께 제공되는 대부분의 로케일에는 동일한 정렬 순서를 갖는 많은 문자(또는 문자 시퀀스(조합 시퀀스))가 있습니다. ■⅕⅖⅗의 경우 순서가 정의되지 않았고 순서가 정의되지 않은 문자는 결국 GNU 시스템에서 동일한 정렬 순서를 갖기 때문입니다. ş 및 Ş와 같은 일부 문자는 동일한 정렬 순서를 갖도록 명시적으로 정의됩니다(물론 이 작업이 수행되는 방식에 대한 명확한 실제 논리나 일관성은 없지만).

이것이 놀랍고 잘못된 행동의 근원입니다. 나는 가지고있다이 질문은 최근 오스틴 패널에서 제기되었습니다.(POSIX 및 단일 UNIX 사양 뒤에 있는 본문) 메일링 리스트, 2015년 4월 3일 현재 논의가 계속 진행 중입니다.

이 경우 위치 와 순서를 동일하게 [y]일치시켜야 하는지 확실하지 않지만 대괄호 표현식은 조합된 요소와 일치하도록 의도되었기 때문에 이는 예상되는 동작임을 나타냅니다.xxybash

어쨌든, 나는 [⅕-⅕]적어도 [⅕-⅖]일치해야 한다고 생각합니다 .

다양한 도구가 다르게 작동한다는 것을 알 수 있습니다. ksh93은 bashGNU 처럼 작동할지 여부 grep입니다 sed. 일부 다른 쉘은 다르게 동작하며 일부는 yash훨씬 더 버그가 많습니다.

일관된 동작을 얻으려면 모든 문자가 다르게 정렬되는 로캘이 필요합니다. C 로캘은 일반적인 로캘입니다. 그러나 대부분의 시스템에서 C 로케일의 문자 세트는 ASCII입니다. GNU 시스템에서는 일반적으로 C.UTF-8UTF-8 문자를 처리하는 데 사용할 수 있는 로케일 에 액세스할 수 있습니다 .

그래서:

(export LC_ALL=C.UTF-8; [[ ■ = [⅕⅖⅗] ]])

또는 이에 상응하는 표준:

(export LC_ALL=C.UTF-8
 case ■ in ([⅕⅖⅗]) true;; (*) false; esac)

false를 반환해야 합니다.

또 다른 대안은 C로 설정하는 것입니다 LC_COLLATE. 이는 GNU 시스템에서는 작동할 수 있지만 멀티바이트 문자에 대한 정렬 순서를 지정할 수 없기 때문에 다른 시스템에서는 반드시 작동할 필요는 없습니다.


교훈 중 하나는평등문자열을 비교할 때 개념은 생각만큼 명확하지 않습니다. 평등은 가장 엄격한 것부터 가장 덜 엄격한 것까지를 의미할 수 있습니다.

  1. 바이트 수는 동일하며 모든 바이트 구성 요소는 동일한 값을 갖습니다.
  2. 문자 수가 동일하고 모든 문자가 동일합니다(예: 현재 문자 세트의 동일한 코드 포인트 참조).
  3. 로케일의 정렬 알고리즘에 따르면 두 문자열의 정렬 순서는 동일합니다(즉, a < b 또는 b > a가 참이 아닙니다).

이제 2 또는 3의 경우 두 문자열에 모두 유효한 문자가 포함되어 있다고 가정합니다. UTF-8 및 일부 기타 인코딩에서는 특정 바이트 시퀀스가 ​​유효한 문자를 형성하지 않습니다.

따라서 일부 문자에는 두 개 이상의 가능한 인코딩이 있을 수 있으므로 1과 2가 반드시 동일하지는 않습니다. 이는 일반적으로 ISO-2022-JP와 같은 상태 저장 인코딩의 경우입니다. A이는 41또는 1b 28 42 41( 1b 28 42ASCII로 전환하는 시퀀스입니다. 원하는 만큼 인코딩을 삽입할 수 있으므로 아무런 차이가 없습니다.) ), 비록 이러한 유형의 인코딩이 여전히 사용되고 있을 것이라고는 예상하지 못하지만, 적어도 일반적으로 GNU 도구는 이러한 유형의 인코딩과 잘 작동하지 않습니다.

또한 GNU가 아닌 대부분의 유틸리티는 0바이트 값(ASCII의 NUL 문자)을 처리할 수 없다는 점에 유의하십시오.

그 중 어느정의사용법은 유틸리티와 유틸리티 구현 또는 버전에 따라 다릅니다. POSIX는 이에 대해 100% 명확하지 않습니다. C 언어 환경에서는 3개 모두 동일합니다. YMMV 외부.

답변2

당신은 잘못하고 있습니다. =그리고 ==그것은 다릅니다.

다음 예를 시도해 보세요.

if [[ "■" == "[⅕⅖⅗]" ]] ; then echo yes ; else echo no ; fi

if [[ "1" == "1" ]] ; then echo yes ; else echo no ; fi

if [[ "■" == "■" ]] ; then echo yes ; else echo no ; fi

관련 정보