쉘 논리 연산자 && 및 ||의 우선순위

쉘 논리 연산자 && 및 ||의 우선순위

Bash에서 논리 연산자 우선순위가 어떻게 작동하는지 이해하려고 합니다. 예를 들어, 다음 명령이 아무 것도 에코할 것으로 예상하지 않습니다.

true || echo aaa && echo bbb

그런데 내 기대와는 다르게 bbb인쇄가 됐다.

누군가 bash에서 복합 연산자 &&와 연산자를 이해하는 방법을 설명해 줄 수 있나요?||

답변1

많은 컴퓨터 언어에서 동일한 우선순위를 갖는 연산자는 다음과 같습니다.좌파노조. 즉, 그룹화 구조가 없는 경우에는 가장 왼쪽의 연산을 먼저 수행한다. 쿵쿵이다예외없이이 규칙에.

Bash와 다른 쉘에서는 우선순위가 동일 &&하기 때문에 이것이 중요합니다. ||이는 일반적 &&으로 ||.

따라서 귀하의 예에서는 ||가장 왼쪽 작업 ( )이 먼저 수행됩니다.

true || echo aaa

true분명히 정확하기 때문에 ||연산자는 단락되고 echo aaa예상대로 평가할 필요 없이 전체 문이 올바른 것으로 간주됩니다. 이제 가장 오른쪽에 있는 작업만 남았습니다.

(...) && echo bbb

첫 번째 작업이 true(즉, 종료 상태가 0)로 평가되므로 다음 작업을 수행하는 것과 같습니다.

true && echo bbb

따라서 &&단락이 발생하지 않으므로 bbb에코가 표시됩니다.

당신은 같은 행동을 할 것입니다

false && echo aaa || echo bbb

댓글을 기반으로 주석 달기

  • 왼쪽 연관성 규칙은 다음과 같습니다.오직두 운영자 모두가같은우선 사항. [[...]]or 같은 키워드 와 함께 이러한 연산자를 사용하거나 or 명령에 대한 인수 로 and 연산자를 ((...))사용하는 경우에는 그렇지 않습니다 . 이 경우 AND가 OR보다 우선 합니다 . 이를 명확히 설명해준 Stephane Chazelas에게 감사드립니다.-o-atest[&&-a||-o

  • 것 같다C에서C와 유사한 언어는 이보다 &&우선순위가 더 높기 ||때문에 아마도 원래 구성이 다음과 같이 동작할 것으로 예상하는 것입니다.

    true || (echo aaa && echo bbb). 
    

그러나 두 연산자의 우선순위가 동일한 Bash의 경우에는 그렇지 않습니다. 이것이 Bash가 표현식을 구문 분석하기 위해 왼쪽 연관성 규칙을 사용하는 이유입니다. 이 점을 제기한 Kevin의 의견에 감사드립니다.

  • 이런 상황도 있을 수 있어요모두 3표현식이 평가됩니다. 첫 번째 명령이 0이 아닌 종료 상태를 반환하는 경우 ||단락되지 않고 두 번째 명령으로 실행이 계속됩니다. 두 번째 명령이 0 종료 상태로 반환되면 &&단락도 발생하지 않으며 세 번째 명령이 실행됩니다. 이 점을 제기한 Ignacio Vazquez-Abrams의 의견에 감사드립니다.

답변2

상황에 따라 여러 항목을 종속시키려면 다음과 같이 그룹화하세요.

true || { echo aaa && echo bbb; }

그 동안 아무것도 인쇄하지 않습니다

true && { echo aaa && echo bbb; }

두 개의 문자열을 인쇄합니다.


이런 일이 일어난 이유는 요셉이 상상했던 것보다 훨씬 간단했습니다. ||Bash가 및 에 대해 무엇을 하는지 기억하세요 &&. 이전 명령의 반환 상태에 관한 것입니다. 원래 명령을 문자 그대로 보는 방법은 다음과 같습니다.

( true || echo aaa ) && echo bbb

true || echo aaa를 종료하는 첫 번째 명령( )입니다 0.

$ true || echo aaa; echo $?
0
$ true && echo aaa; echo $?
aaa
0

$ false && echo aaa; echo $?
1
$ false || echo aaa; echo $?
aaa
0

답변3

&&그리고 운영자 ||아니요if-then-else에 대한 정확한 인라인 대체. 그러나 올바르게 사용하면 동일한 결과를 얻을 수 있습니다.

단일 테스트는 간단하고 모호하지 않습니다.

[[ A == A ]]  && echo TRUE                          # TRUE
[[ A == B ]]  && echo TRUE                          # 
[[ A == A ]]  || echo FALSE                         # 
[[ A == B ]]  || echo FALSE                         # FALSE

그러나 여러 테스트를 추가하려고 하면 예상치 못한 결과가 발생할 수 있습니다...

[[ A == A ]]  && echo TRUE   || echo FALSE          # TRUE  (as expected)
[[ A == B ]]  && echo TRUE   || echo FALSE          # FALSE (as expected)
[[ A == A ]]  || echo FALSE  && echo TRUE           # TRUE  (as expected)
[[ A == B ]]  || echo FALSE  && echo TRUE           # FALSE TRUE   (huh?)

둘 다 거짓인 이유그리고TRUE가 에코되었나요?

여기서 일어나는 일은 우리가 그것을 깨닫지 못하고 오버로드된 연산자이며 &&여기 에 있는 AND 및 OR(조건부 실행) 목록과 조건부 테스트 대괄호 내에서 다르게 ||동작한다는 것입니다 .[[ ]]

bash 맨페이지에서 (편집됨)...

목록

목록은 &, && 또는 ││ 연산자 중 하나로 구분되고 선택적으로;, & 또는 or 중 하나로 끝나는 하나 이상의 파이프 시퀀스입니다. 이러한 목록 연산자 중에서 &&와 │는 동일한 우선순위를 갖고 그 다음에는 동일한 우선순위를 갖는 &가 있습니다.

명령을 구분하기 위해 세미콜론 대신 일련의 하나 이상의 줄 바꿈이 목록에 나타날 수 있습니다.

명령이 제어 연산자 &로 끝나면 쉘은 서브쉘의 백그라운드에서 명령을 실행합니다. 쉘은 명령이 완료될 때까지 기다리지 않고 상태 0을 반환합니다. ;로 구분된 명령은 순차적으로 실행됩니다. 쉘은 각 명령이 차례로 종료될 때까지 기다립니다. 반환 상태는 마지막으로 실행된 명령의 종료 상태입니다.

AND 및 OR 목록은 각각 && 및 │ 제어 연산자로 구분된 여러 파이프 중 하나의 시퀀스입니다. AND 및 OR 목록은 왼쪽 연관성으로 수행됩니다.

AND 목록의 형식은 다음과 같습니다...
command1 && command2
Command2는 command1이 종료 상태 0을 반환하는 경우에만 실행됩니다.

OR 목록의 형식은 다음과 같습니다...
command1 ││ command2
Command2는 command1이 0이 아닌 종료 상태를 반환하는 경우에만 실행됩니다.

AND 및 OR 목록의 반환 상태는 목록에서 마지막으로 실행된 명령의 종료 상태입니다.

마지막 예로 돌아가서...

[[ A == B ]]  || echo FALSE  && echo TRUE

[[ A == B ]]  is false

     ||       Does NOT mean OR! It means...
              'execute next command if last command return code(rc) was false'

 echo FALSE   The 'echo' command rc is always true
              (i.e. it successfully echoed the word "FALSE")

     &&       Execute next command if last command rc was true

 echo TRUE    Since the 'echo FALSE' rc was true, then echo "TRUE"

좋아요 이것이 맞다면, 두 번째 예가 왜 아무 것도 반영하지 않습니까?

[[ A == A ]]  || echo FALSE  && echo TRUE


[[ A == A ]]  is true

     ||       execute next command if last command rc was false.

 echo FALSE   Since last rc was true, shouldn't it have stopped before this?
                Nope. Instead, it skips the 'echo FALSE', does not even try to
                execute it, and continues looking for a `&&` clause.

     &&       ... which it finds here

 echo TRUE    ... so, since `[[ A == A ]]` is true, then it echos "TRUE"

여러 개를 사용하거나 명령 목록에서 사용하는 경우 &&논리 ||오류가 발생할 위험이 상당히 높습니다.

제안

명령 목록의 단일 OR은 &&예상대로 작동하므로 매우 안전합니다. ||else 절이 필요하지 않은 경우 다음을 더 명확하게 따를 수 있습니다(마지막 2개의 명령을 그룹화하려면 중괄호가 필요함)...

[[ $1 == --help ]]  && { echo "$HELP"; exit; }

마지막을 제외한 각 명령이 테스트인 다중 &&||연산자(예: 대괄호 안 [[ ]])도 마지막 연산자를 제외한 모든 연산자가 예상대로 작동하므로 일반적으로 안전합니다. 마지막 연산자는 thenor else절과 유사하게 작동합니다.

답변4

저도 이것에 대해 혼란스럽습니다. 하지만 Bash가 명령문을 읽는 방식에 대한 저의 견해는 다음과 같습니다(기호를 왼쪽에서 오른쪽으로 읽으므로):

  1. 기호를 찾으십시오 true. 명령 끝에 도달하면 이를 평가해야 합니다. 현재로서는 논란이 있는지는 모르겠습니다. 실행 버퍼에 명령을 저장합니다.
  2. 기호를 찾았습니다 ||. 이제 이전 명령이 완료되었으므로 평가해 보세요. 실행 중인 명령(버퍼): true.평가 결과: 0(즉, 성공). 결과 0을 "마지막 평가" 레지스터에 저장합니다. 이제 상징 ||자체를 생각해 보십시오. 이는 마지막 평가 결과가 0이 아닌지에 따라 달라집니다. "마지막 평가" 레지스터를 확인한 결과 0이 발견되었습니다. 0은 0이 아닌 값이 아니므로 다음 명령을 평가할 필요가 없습니다.
  3. 기호를 찾았습니다 echo. 다음 명령을 평가할 필요가 없으므로 기호를 무시할 수 있습니다.
  4. 기호 찾기 aaa이것은 명령 (3)에 대한 인수이지만 echo( echo3)을 평가할 필요가 없으므로 무시할 수 있습니다.
  5. 기호를 찾으십시오 &&. 이는 마지막 평가 결과가 0인지 여부에 따라 다릅니다. "마지막 평가" 레지스터를 확인한 결과 0이 발견되었습니다. 0은 0이므로 다음 명령을 평가해야 합니다.
  6. 기호를 찾으십시오 echo. 명령 끝에 도달하면 다음 명령을 평가해야 하므로 명령을 평가해야 합니다. 실행 버퍼에 명령을 저장합니다.
  7. 기호 찾기 bbb이것은 echo명령(6)에 대한 인수입니다. echo평가가 필요 하므로 bbb실행 버퍼에 추가됩니다.
  8. 줄의 끝에 도달했습니다. 이제 이전 주문이 완료되었으며 평가가 필요합니다. 실행 중인 명령(버퍼): echo bbb.평가 결과: 0(즉, 성공). 결과 0을 "마지막 평가" 레지스터에 저장합니다.

물론 마지막 단계에서는 bbb콘솔에 에코가 발생합니다.

관련 정보