Bash의 조건이 다른 경우

Bash의 조건이 다른 경우

if else3개의 부울 변수를 사용하는 bash 스크립트를 만들려고 합니다 .

  1. CHECK_X
  2. CHECK_Y
  3. CHECK_Z

만약 CHECK_X아니면CHECK_Y잘못된그리고 또한 CHECK_Z,잘못된그런 다음 조건이 충족되지 않았음을 사용자에게 알립니다. 그래서 다음을 만들었습니다.

if [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && [[ "$CHECKZ" == "FALSE" ]]; then
  echo "Condition not met"
fi

위의 코드를 사용하여 CHECK_X또는 CHECK_Y올바른 경우에도 CHECK_Z여전히잘못된이런 일이 계속된다면 내가 원하는 것은 이것이 아니다.

나는 이것들 중 하나가 필요 CHECK_X하고CHECK_Z진짜아니면 CHECK_Y되고CHECK_Z진짜내 조건이 충족될 때까지.

다음 코드를 사용해도 작동하지 않습니다.

if [[ "$CHECK_X" && "$CHECK_Z" == "FALSE" ]] || [[ "$CHECK_Y" && "$DCHECK_Z" == "FALSE" ]]; then
  echo "Condition not met"
fi    

어딘가 너무 복잡하다고 생각하고 전문가의 조언이 필요합니다. 감사해요

고쳐 쓰다:

최근 피드백을 바탕으로 코드를 다음과 같이 업데이트했습니다.

if [[ "$CHECK_X" == "FALSE" || "$CHECK_Y" == "FALSE" ]] && [[ "$CHECK_Z" == "FALSE" ]]; then
  echo "Condition not met"
fi

그러나 테스트 후 나는 다음과 같은 것을 얻었습니다 ...

만약에:

  1. CHECK_X="TRUE"
  2. CHECK_Y="FALSE"
  3. CHECK_Z="TRUE"

출력: Condition not met. 이것은잘못된조건 때문에1그리고TRUE.

만약에:

  1. CHECK_X="TRUE"
  2. CHECK_Y="FALSE"
  3. CHECK_Z="FALSE"

출력: Condition not met. 이것은옳은조건 때문에1그리고모두아니요 TRUE.

만약에:

  1. CHECK_X="FALSE"
  2. CHECK_Y="TRUE"
  3. CHECK_Z="FALSE"

출력: 스크립트가 완료되었습니다. 이것은잘못된조건 때문에2그리고아니요 TRUE.

만약에:

  1. CHECK_X="FALSE"
  2. CHECK_Y="TRUE"
  3. CHECK_Z="TRUE"

출력: 스크립트가 완료되었습니다. 이것은옳은조건 때문에2그리고TRUE.

만약에:

  1. CHECK_X="FALSE"
  2. CHECK_Y="FALSE"
  3. CHECK_Z="FALSE"

출력: Condition not met. 이것은옳은조건 때문에1그리고또는2그리고아니요 TRUE.

답변1

각 변수를 확인해야 합니다.

if [[ "$CHECKX" == "FALSE" || "$CHECKY" == "FALSE" ]] && [[ "$CHECKZ" == "FALSE" ]]; then
  echo "Condition not met"
fi

때때로 , 이것은 설정되어 있는지 if [[ "$CHECKX" || "$CHECKY" == "FALSE" ]]확인하고 문자열과 비교합니다 . 표시하려면:$CHECKX$CHECKYFALSE

$ CHECKX=foo
$ CHECKY=TRUE
$ [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && echo true
true
$ CHECKX=""
$ [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && echo true
$ 

위에서 볼 수 있듯이 빈 문자열로 설정된 경우에만 검사가 실패하므로 CHECKX테스트는 [[ "$CHECKX" ]]false로 평가됩니다. 다음을 포함한 임의의 값으로 설정된 경우 0:

$ CHECKX=0
$ [[ "$CHECKX" || "$CHECKY" == "FALSE" ]] && echo true
true

답변2

다른 사람들은 이미 부울 값과 변수를 저장하고 테스트하는 코딩 기술을 다루었으므로 저는 코드의 논리에만 집중하겠습니다.

다변수 부울 함수를 작업할 때진리표이렇게 하면 함수의 올바른 출력이 무엇인지 알 수 있습니다. 귀하의 게시물을 올바르게 이해했는지 확인하십시오. 그러나 함수의 경우 Q(X,Y,Z)값은 다음 과 같이 에 따라 Q달라집니다 .XYZ

"X 또는 Y가 거짓이고 Z가 거짓이면... 조건이 충족되지 않습니다."

귀하가 이미 이를 거부했으므로 다른 모든 경우에는 다음 조건이 적용된다고 가정하겠습니다.만났다.

엑스 묻다
잘못된 잘못된 잘못된 잘못된
잘못된 잘못된 진짜 진짜
잘못된 진짜 잘못된 잘못된
잘못된 진짜 진짜 진짜
진짜 잘못된 잘못된 잘못된
진짜 잘못된 진짜 진짜
진짜 진짜 잘못된 진짜
진짜 진짜 진짜 진짜

부울 대수의 일반적인 공리는 모든 경우를 해결하기 위해 하나의 함수 Q를 구성하는 대신 테이블의 상호 배타적인 부분을 해결하기 위해 두 개의 하위 함수 Q1과 Q2를 구성할 수 있다는 것입니다. 그런 다음 ORQ1과 Q2의 결과를 간단히 처리하여 최종 솔루션 Q를 얻을 수 있습니다.

예를 들어, X표의 위쪽 절반에 있는 Q1을 FALSE 솔루션으로 가정합니다. Z및 열은 네 가지 경우 모두 Q동일합니다 . 이 열은 관련이 없으므로 FALSE일 때 함수 결과는 직접적으로 종속된다고 Y말할 수 있습니다 .XZ

for X=FALSE, Q1 = !X && Z
엑스 1분기
잘못된 잘못된 잘못된 잘못된
잘못된 잘못된 진짜 진짜
잘못된 진짜 잘못된 잘못된
잘못된 진짜 진짜 진짜

테이블 하단에서 XTRUE인 경우 함수 결과 Q2는 다음과 직접 관련됩니다 Y || Z.

for X=TRUE, Q2 = X && (Y || Z)
엑스 2분기
진짜 잘못된 잘못된 잘못된
진짜 잘못된 진짜 진짜
진짜 진짜 잘못된 진짜
진짜 진짜 진짜 진짜

Q1과 Q2는 완전히 독립된 영역에 정의되어 있으므로 결과 Q는 정확히 둘 중 하나라고 말할 수 있습니다. 그건,

Q = Q1 || Q2
엑스 1분기 2분기 1분기 || 2분기
잘못된 잘못된 잘못된 잘못된 잘못된
잘못된 잘못된 진짜 진짜 진짜
잘못된 진짜 잘못된 잘못된 잘못된
잘못된 진짜 진짜 진짜 진짜
진짜 잘못된 잘못된 잘못된 잘못된
진짜 잘못된 진짜 진짜 진짜
진짜 진짜 잘못된 진짜 진짜
진짜 진짜 진짜 진짜 진짜

이제 이 두 가지 상황을 부울 공식으로 결합해야 합니다. 단순히 모든 것을 연결하고 싶은 유혹이 있지만 올바른 부울 공식을 위해서는 계산 순서를 고려해야 합니다. 덧셈 전에 곱셈이 수행되는 일반 대수와 유사하게, 부울 대수는 합집합(OR) 전에 교차(AND)가 수행되도록 지시합니다. 따라서 하위 표현식 주위에 괄호를 넣습니다.

둘 다 X거짓이며 결과는 다음과 같습니다 Z.

if !X then Q1 = Z

아니면 X그것이 사실인가요? 결과는 다음과 같습니다 Y || Z.

if  X then Q2 = Y || Z

우리의 대답은 실제로 둘 중 하나입니다.

Q = (!X && Q1) || (X && Q2)

단락 평가와 정류를 결합하면 이를 다음과 같이 재구성할 수 있습니다.

Q = (X && Q2) || (Q1)

Q1과 Q2를 대체하면 다음과 같습니다.

Q = (X && (Y || Z)) || (Z)

필요한 경우에만 괄호를 사용하세요.

Q = X && (Y || Z) || Z

다음과 같이 작성할 수도 있습니다.

Q = Z || X && (Y || Z) 

Z가 참인 경우 OR의 오른쪽은 중요하지 않습니다. Z가 false인 경우 OR의 오른쪽은 다음과 같습니다.

X && (Y || FALSE)

그렇지 않으면:

X && Y

따라서 최종 함수 Q는 다음과 같습니다.

Q = Z || X && Y

각 경우에 Z가 참일 때 Q도 참이기 때문에 우리는 진리표를 기반으로 이를 확인할 수 있습니다. Z가 거짓인 네 가지 경우에서 Q는 X와 Y가 모두 참인 경우에만 참입니다.

엑스 X && Y 묻다
잘못된 잘못된 잘못된 잘못된 잘못된
잘못된 잘못된 진짜 잘못된 진짜
잘못된 진짜 잘못된 잘못된 잘못된
잘못된 진짜 진짜 잘못된 진짜
진짜 잘못된 잘못된 잘못된 잘못된
진짜 잘못된 진짜 잘못된 진짜
진짜 진짜 잘못된 진짜 진짜
진짜 진짜 진짜 진짜 진짜

답변3

귀하의 요청을 [복수] 이중 부정으로 표현하십시오("CHECK_X 또는 CHECK_Y가잘못된CHECK_Z도 마찬가지입니다.잘못된그런 다음 사용자에게 조건이 다음과 같다고 알립니다.아니요만나다. ”) 긍정적인 방식으로 표현하는 것보다 이해하고 구현하는 것이 훨씬 더 어렵습니다.

요구 사항이나 코드에 !or 또는 비교와 같은 부정적인 단어를 사용하지 not말고 변수 이름에 부정적인 용어를 사용하지 마십시오. 같은 이유로 긍정은 항상 부정적인 것보다 이해하기 쉽고, 부정적인 것이 없으면 다음을 수행할 수 있습니다. 이해하기 매우 어려운 이중 부정으로 끝나지 않습니다.falsenot

귀하의 요구 사항은 다음과 같습니다.

CHECK_X 또는 CHECK_Y가 false이고 CHECK_Z가 false인 경우 조건이 충족되지 않음을 사용자에게 알립니다.

귀하의 요구 사항을 의사 코드로 직접 변환할 수 있습니다.

if ( ((CHECK_X == false) || (CHECK_Y == false)) && (CHECK_Z == false) ); then
    print 'conditions are not met'
else
    conditions are met so do nothing
fi

if이제 부정적인 영향을 줄이기 위해 먼저 "조건 충족"(즉, 부정적 대신 긍정적)을 테스트 중인 조건으로 만들면 다음과 같이 됩니다.

if ! ( ((CHECK_X == false) || (CHECK_Y == false)) && (CHECK_Z == false) ); then
    conditions are met so do nothing
else
    print 'conditions are not met'
fi

이제 if부정적인 "조건이 충족됨" 대신 긍정적인 "조건이 충족됨"을 얻을 수 있는 테스트가 생겼습니다.아니요이제 선행 "not" 연산자를 제외하고 AND 비교를 AND 비교로 변경하여 if테스트 자체를 부정적인 대신 긍정적으로 만들기 만 하면 됩니다.!falsetrue

부울 대수학을 적용하여 가장 바깥쪽 괄호 안의 음수를 이동하면 !조건은 다음과 같습니다.

if ( !((CHECK_X == false) || (CHECK_Y == false)) || !(CHECK_Z == false) ); then
    conditions are met so do nothing
else
    print 'conditions are not met'
fi

동일한 방법을 다시 적용하여 !적용되는 조건 내에서 첫 번째 방법을 이동하면 다음과 같은 결과를 얻습니다.

if ( ( !(CHECK_X == false) && !(CHECK_Y == false) ) || !(CHECK_Z == false) ); then
    conditions are met so do nothing
else
    print 'conditions are not met'
fi

각각을 다음과 같이 변경하여 !...false단순화 할 수 있습니다 true.

if ( ((CHECK_X == true) && (CHECK_Y == true)) || (CHECK_Z == true) ); then
    conditions are met so do nothing
else
    print 'conditions are not met'
fi

이제 "조건이 충족되었습니다"라는 긍정적인 결과를 생성하는 완전히 긍정적인 테스트가 있으므로 if갑자기 요구 사항이 단순하다는 것이 매우 명확해집니다. CHECK_Z 또는 CHECK_X 및 CHECK_Y가 모두 true이면 조건이 충족되고 그렇지 않으면 조건 t가 충족됩니다. , 따라서 if-else위의 방법이나 보다 간결한 접근 방식을 사용하여 이 요구 사항을 쉽게 구현할 수 있습니다.

$ cat tst.sh
#!/usr/bin/env bash

testit() {
    [[ (("$CHECK_X" == "TRUE") && ("$CHECK_Y" == "TRUE")) || ("$CHECK_Z" == "TRUE") ]] ||
        printf 'conditions are not met\n'
}

for CHECK_X in TRUE FALSE; do
    for CHECK_Y in TRUE FALSE; do
        for CHECK_Z in TRUE FALSE; do
            printf 'CHECK_X=%s, CHECK_Y=%s, CHECK_Z=%s %s\n' \
                    "$CHECK_X" "$CHECK_Y" "$CHECK_Z" "$(testit)"
        done
    done
done

$ ./tst.sh
CHECK_X=TRUE, CHECK_Y=TRUE, CHECK_Z=TRUE
CHECK_X=TRUE, CHECK_Y=TRUE, CHECK_Z=FALSE
CHECK_X=TRUE, CHECK_Y=FALSE, CHECK_Z=TRUE
CHECK_X=TRUE, CHECK_Y=FALSE, CHECK_Z=FALSE conditions are not met
CHECK_X=FALSE, CHECK_Y=TRUE, CHECK_Z=TRUE
CHECK_X=FALSE, CHECK_Y=TRUE, CHECK_Z=FALSE conditions are not met
CHECK_X=FALSE, CHECK_Y=FALSE, CHECK_Z=TRUE
CHECK_X=FALSE, CHECK_Y=FALSE, CHECK_Z=FALSE conditions are not met

답변4

BASH에서 부울 값을 원할 경우 실제 부울 값에 가장 가까운 방법은 다음을 사용하는 것입니다.
숫자와 쉘 연산.

이유: CHECK_X="true"; [[ $CHECK_X == "true" ]];
올바른 인수가 glob 패턴(인용되지 않은 경우)이고 부울, 종료 코드 0 또는 1과 같은 것을 생성하는 문자열 비교입니다 .

쉘 연산을 시도해 보십시오:

set +o histexpand # only needed in an interactive shell

declare -i CHECK_X=0 CHECK_Y=0 CHECK_Z=0   #-- Boolean 0 or 1 , false or true

# now you can use boolean syntax inside shell arithmetic ((...))
if (( (!CHECK_X || !CHECK_Y) && !CHECK_Z )); then echo "yep"; fi
if (( CHECK_X || CHECK_Y || !CHECK_Z )); then echo "pep"; fi

declare test="hello"  # with string
if (( CHECK_X && CHECK_Y && CHECK_Z && test=="hello" )); then echo ".."; fi

관련 정보