변수에 부울 비교 값 할당

변수에 부울 비교 값 할당

문자열 변수의 내용 간에 가능한 모든 비교를 수행해야 하는 스크립트가 있습니다. 각 조합에는 변수 내용에 대한 서로 다른 접근 방식이 필요하므로 다음과 같습니다.

if $a contains "a" AND "b" AND "c"; then do x
elif $a contains "a" AND "b" but NOT "c"; then do y
elif $a contains "b" AND "c" but NOT "a"; then do z
...

내가 아는 한, 이를 수행하는 방법은 다음과 같은 if 조건을 구성하는 것입니다.

if [[ $A == *"b"* ]] && [[ $A == *"c"* ]] && [[ $A == *"d"* ]]
elif [[ $A == *"b"* ]] && [[ $A == *"c"* ]]
elif [[ $A == *"c"* ]] && [[ $A == *"d"* ]]
elif [[ $A == *"b"* ]] && [[ $A == *"d"* ]]
elif [[ $A == *"b"* ]]
elif [[ $A == *"c"* ]]
elif [[ $A == *"d"* ]]
fi

그러나 물론 변수 이름($A)과 하위 문자열(b, c, d)이 이보다 훨씬 길기 때문에 오류 없이 읽고 이해하고 쓰기에는 너무 복잡합니다. 그래서 조건식의 내용을 변수에 저장하는 방법이 있는지 알아보고 싶었습니다.

contains_b= *a condition for [[ $A == *"b"* ]]*; echo $contains_b-> 참|거짓

답글만 찾았어요여기[ contains_b=$(! [ "$A" = *"b"* ]; echo $?)]; 그러나 다음과 같은 $contains_b -> 0이유로 후속 조건에서는 작동하지 않습니다.

if $contains_b; then do x; fi->bash: [0]: command not found

그래서 제가 생각할 수 있는 유일한 해결책은 수동으로 수행하는 것입니다.

if [[ $A == *"b"* ]]; then
    contains_b=true
else
    contains_b=false
fi

그러나 결국 세 개의 변수를 얻기 위해 세 개의 if 문을 실행하고 각각의 다른 조합에 대해 7개의 다른 비교를 수행하게 됩니다.

이 작업을 수행하는 다른/더 효율적인 방법이 있는지 궁금합니다. 그렇지 않은 경우 다중 비교를 수행하는 다른 방법에 대한 제안 사항이 있습니까? 일을 너무 복잡하게 만드는 것 같은 느낌이 드네요...

도움을 주셔서 감사합니다.

답변1

바이너리 마스크를 생성한 다음 이에 대해 작업을 수행합니다. 이것의 이점은 각 테스트가 한 번만 실행되고 테스트 결과에 대한 조치와 테스트를 분리한다는 것입니다.

코드에서는 패턴을 확장 정규식으로 사용합니다. 문자열로 비교하려면 다음을 사용하십시오.

[[ $string == *"$pattern"* ]]

바꾸다

[[ $string =~ $pattern ]]

아래 코드에서.

patterns=( a b c )
string='abba'

mask=0; i=0
for pattern in "${patterns[@]}"; do
        if [[ $string =~ $pattern ]]; then
                # setting the i:th bit from the right to one
                mask=$(( mask | (1 << i) ))
        fi
        i=$(( i + 1 ))
done

case $mask in
        0) echo no match ;;
        1) echo first pattern matched ;;
        2) echo second pattern matched ;;
        3) echo first and second pattern matched ;;
        4) echo third pattern matched ;;
        5) echo first and third pattern matched ;;
        6) echo second and third pattern matched ;;
        7) echo all patterns matched ;;
        *) echo error
esac

또는 1과 0(일치 없음의 경우 0, 일치의 경우 1)이 포함된 문자열 마스크를 사용합니다. 아래 문자열은 mask위 코드에 사용된 숫자의 실제 이진 표현과 반대라는 점에 유의하세요.

patterns=( a b c )
string='abba'

unset -v mask
for pattern in "${patterns[@]}"; do
        ! [[ $string =~ $pattern ]]
        # string concatenation of the exit status of the previous command
        mask+=$?
done

case $mask in
        000) echo no match ;;
        100) echo first pattern matched ;;
        010) echo second pattern matched ;;
        110) echo first and second pattern matched ;;
        001) echo third pattern matched ;;
        101) echo first and third pattern matched ;;
        011) echo second and third pattern matched ;;
        111) echo all patterns matched ;;
        *) echo error
esac

각 스크립트의 출력은 다음과 같습니다.

first and second pattern matched

...문자열이 abba처음 두 패턴과 일치 a하고 b.

답변2

이것과 함께bash4.0또는 위 또는mkshR40case이상에서는 두 가지 명령문으로 모든 작업을 수행할 수 있습니다.

a=n b=n c=n
case $string in
  (*a*) a=y ;;&
  (*b*) b=y ;;&
  (*c*) c=y
esac
case $a$b$c in
  (nnn) echo none   ;;
  (ynn) echo a only ;;
  (yyn) echo ab     ;;
  (yyy) echo all    ;;
    (*) echo other
esac

이것zshbash 해당;;&;|, 반품서포터mksh.

답변3

나는 [여기][1]에서만 답장을 찾았지만 contains_b=$(! [ "$A" = *"b"* ]; echo $?)]다음과 $contains_b -> 0같은 이유로 후속 조건에서는 작동하지 않습니다.

if $contains_b; then do x; fi->bash: [0]: command not found

숫자 결과를 얻은 후에는 명령으로 실행하는 대신 산술 연산을 수행해야 합니다.

contains_a=$(! [[ $A == *$pattern_a* ]]; echo $?)
contains_b=$(! [[ $A == *$pattern_b* ]]; echo $?)
contains_c=$(! [[ $A == *$pattern_c* ]]; echo $?)

if (( contains_a && contains_b && contains_c )); then
    echo all
elif (( contains_a && contains_b )); then
    echo ab
...
fi

답변4

=~Bash에서 정규식 일치를 사용하여 가능한 각 일치 패턴을 한 번만 테스트함으로써 바이너리를 생성할 수 있습니다. 올바른 순서(MSB가 보존되고 마지막으로 실행된 테스트에 해당)로 바이너리를 빌드하려면 (음수) 종료 코드를 변수에 추가해야 합니다.

#!/bin/bash --

string=${1:-"abba"}

patterns=( a b c )

unset bin
for re in "${patterns[@]}"; do
    ! [[ $string =~ $re ]]; bin="$?$bin"
done

case $((2#$bin)) in
        0) echo no match ;;
        1) echo first pattern matched ;;
        2) echo second pattern matched ;;
        3) echo first and second pattern matched ;;
        4) echo third pattern matched ;;
        5) echo first and third pattern matched ;;
        6) echo second and third pattern matched ;;
        7) echo all patterns matched ;;
        *) echo error
esac

이전 답변에 대한 대체 솔루션입니다.

관련 정보