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


126

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

true || echo aaa && echo bbb

그러나 내 기대와 달리 bbb인쇄됩니다.

누군가 bash에서 복합 &&||연산자를 어떻게 이해할 수 있습니까?

답변:


127

많은 컴퓨터 언어에서 우선 순위가 같은 연산자는 왼쪽 연관 입니다. 즉, 그룹화 구조가 없으면 가장 왼쪽의 작업이 먼저 실행됩니다. 배쉬 도이 규칙에서 예외아닙니다 .

배쉬에서, 때문에 중요 &&하고 ||우선 순위가 동일합니다.

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

true || echo aaa

true분명히 사실 이기 때문에 , ||작업자 단락 및 전체 설명은 echo aaa예상대로 평가할 필요없이 사실로 간주됩니다 . 이제 가장 올바른 작업을 수행해야합니다.

(...) && echo bbb

첫 번째 작업이 true로 평가되었으므로 (즉, 종료 상태가 0 임) 마치 마치 실행중인 것처럼

true && echo bbb

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

당신은 같은 행동을 얻을 것이다

false && echo aaa || echo bbb

주석을 기반으로 한 메모

  • 왼쪽 연관 규칙은 두 연산자 우선 순위 가 동일한 경우 에만 따라야 합니다. 당신과 같은 키워드와 함께 이러한 연산자를 사용하면 이런 일이 발생하지 않습니다 거나 또는 사용 및 받는 인수로 사업자 또는 명령. 이러한 경우 AND ( 또는 )가 OR ( 또는 ) 보다 우선 합니다. 이 점을 명확히 한 Stephane Chazelas의 의견에 감사드립니다.[[...]]((...))-o-atest[&&-a||-o
  • 것으로 보인다 C에서 와 C 같은 언어가 &&더 높은 우선 순위를 가지고보다 ||당신처럼 행동하는 원래의 구조를 예상 이유 아마

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

    그러나 Bash의 경우에는 두 연산자가 모두 동일한 우선 순위를 가지므로 Bash는 왼쪽 연관 규칙을 사용하여 식을 구문 분석합니다. 이것을 제기 한 Kevin의 의견에 감사드립니다.

  • 또한 경우가있을 수 있습니다 3 식이 평가됩니다. 첫 번째 명령이 0이 아닌 종료 상태를 반환하면 ||단락되지 않고 두 번째 명령을 계속 실행합니다. 두 번째 명령이 종료 상태 0으로 돌아 가면 &&단락되지 않으며 세 번째 명령이 실행됩니다. 이 문제를 제기 한 Ignacio Vazquez-Abrams의 의견에 감사드립니다.


26
조금 더 혼란을주는 주목할만한 참고 사항 : &&and 및 ||shell 연산자는 cmd1 && cmd2 || cmd3우선 순위가 같지만 &&in ((...))[[...]]우선 순위는 ||( ((a || b && c))is ((a || (b && c))))입니다. 동일은 간다 -a/ -o에서 test/ [find&/ |expr.
Stéphane Chazelas

16
c와 같은 언어에서는의 &&우선 순위가 높 ||으므로 OP의 예상되는 동작이 발생합니다. 이러한 언어에 익숙하지 않은 사용자는 bash에서 동일한 우선 순위를 가지고 있다는 것을 인식하지 못할 수 있으므로 bash에서 동일한 우선 순위를 가지고 있음을보다 명확하게 지적 할 가치가 있습니다.
케빈

또한 중간 명령이 true 또는 false를 반환 할 수있는 경우와 같이 세 가지 명령을 모두 실행할 수있는 상황이 있습니다 .
이그나시오 바스케스-아 브람스

@Kevin 수정 된 답변을 확인하십시오.
Joseph R.

1
오늘, "bash operator priority "에 대한 Google의 인기는 tldp.org/LDP/abs/html/opprecedence.html 입니다. &&는 ||보다 우선 순위가 높습니다. 그러나 @JosephR. 사실과 옳은 법칙이기도합니다. 대시는 pubs.opengroup.org/onlinepubs/009695399/utilities/… 에서 동일한 동작을 수행하고 "우선 순위"를 검색합니다 . POSIX 요구 사항이므로이를 확인할 수 있습니다. 내가 버그보고에서 찾은 것은 저자의 이메일 주소였으며, 지난 6 년 동안 스팸으로 확인되었습니다. 어쨌든 시도하겠습니다 ...
Martin Dorey

62

여러 가지 사항을 조건에 따라 설정하려면 다음을 그룹화하십시오.

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

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

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

두 문자열을 인쇄합니다.


이것이 일어나는 이유는 요셉이 만드는 것보다 훨씬 간단합니다. 강타와 함께 무엇을 기억 ||하고 &&. 이전 명령의 반환 상태에 관한 것입니다. 원시 명령을 보는 문자 그대로의 방법은 다음과 같습니다.

( 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

7
+1 OP의 의도 된 결과 달성. 괄호 (true || echo aaa) && echo bbb는 내가 만들고있는 것입니다.
Joseph R.

1
세계의 이쪽에서 @Oli를 만나서 반갑습니다.
Braiam

7
;맨 끝에 세미 열이 있습니다. 이것이 없으면 작동하지 않습니다!
Sroo Stroobandt

2
마지막 명령 (예 : echo bbb;첫 번째 예) 후 세미콜론이 누락되어 문제가 발생했습니다 . 내가 그것을 잃어 버렸다는 것을 알았을 때,이 대답은 내가 찾던 것입니다. 내가 원하는 것을 달성하는 방법을 알아낼 수 있도록 도와주는 +1!
Doktor J

5
혼란 (...){...}표기법 을 가진 사람을위한 가치있는 독서 : 명령 그룹화 매뉴얼
ANTARA

16

&&||운영자는되어 있지 경우 - 당시 다른 인라인 교체 정확한. 조심스럽게 사용하더라도 그들은 거의 같은 일을 할 수 있습니다.

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

[[ 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?)

FALSE TRUE 가 모두 에코되는 이유는 무엇 입니까?

여기에서 일어나고있는 것은 우리가 그것을 실현하지 않아도된다는 것입니다 &&||조건 테스트 대괄호 안에 다르게 행동 사업자 오버로드 [[ ]]그들이 AND에서 할 수 및 OR (조건부 실행) 목록은 우리가 여기보다 더합니다.

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

기울기

리스트는 연산자;, &, && 또는 ││ 중 하나로 분리되고 선택적으로;, &, 또는로 종료되는 하나 이상의 파이프 라인 시퀀스입니다. 이 목록 연산자 중 &&와 ││의 우선 순위는 같고; 우선 순위가 같은 & &.

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

제어 연산자 &에 의해 명령이 종료되면, 쉘은 서브 쉘의 백그라운드에서 명령을 실행합니다. 쉘은 명령이 완료되기를 기다리지 않고 리턴 상태는 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"

둘 이상 &&또는 ||명령 목록에서 사용할 때 논리 오류의 위험 이 매우 높습니다.

추천

단일 &&또는 ||명령 목록에 예상대로 작동하므로 매우 안전합니다. else 절이 필요하지 않은 상황이라면 다음과 같은 것이 더 명확 해 질 수 있습니다 (마지막 중괄호는 마지막 두 명령을 그룹화해야합니다) ...

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

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


0

나는 이것에 혼란스러워하지만 여기 Bash가 당신의 진술을 읽는 방식에 대해 어떻게 생각하는지가 있습니다 (왼쪽에서 오른쪽으로 기호를 읽음).

  1. 기호를 찾았습니다 true. 명령의 끝에 도달하면이를 평가해야합니다. 이 시점에서 인수가 있는지 모릅니다. 실행 버퍼에 명령을 저장하십시오.
  2. 기호를 찾았습니다 ||. 이전 명령이 완료되었으므로 평가하십시오. 실행중인 명령 (버퍼) : true. 평가 결과 : 0 (즉, 성공). "마지막 평가"레지스터에 결과 0을 저장하십시오. 이제 기호 ||자체를 고려하십시오 . 이는 마지막 평가 결과가 0이 아닌 결과에 따라 다릅니다. "마지막 평가"레지스터를 점검하고 0을 찾았습니다. 0이 0이 아니므로 다음 명령을 평가할 필요가 없습니다.
  3. 기호를 찾았습니다 echo. 다음 명령을 평가할 필요가 없으므로이 기호를 무시할 수 있습니다.
  4. 기호를 찾았습니다 aaa. 이것은 명령 echo(3)에 대한 인수 이지만 echo(3)을 평가할 필요가 없으므로 무시할 수 있습니다.
  5. 기호를 찾았습니다 &&. 이것은 마지막 평가 결과가 0 인 것에 달려 있습니다. "마지막 평가"레지스터를 점검하고 0을 찾았습니다. 0이 0이므로 다음 명령을 평가해야합니다.
  6. 기호를 찾았습니다 echo. 다음 명령을 평가해야했기 때문에 명령 끝에 도달하면이 명령을 평가해야합니다. 실행 버퍼에 명령을 저장하십시오.
  7. 기호를 찾았습니다 bbb. 이것은 명령 echo(6)에 대한 인수 입니다. echo평가가 필요 했기 때문에 bbb실행 버퍼에 추가하십시오 .
  8. 줄의 끝에 도달했습니다. 이전 명령이 완료되었으며 평가가 필요했습니다. 실행중인 명령 (버퍼) : echo bbb. 평가 결과 : 0 (즉, 성공). "마지막 평가"레지스터에 결과 0을 저장하십시오.

물론 마지막 단계 bbb는 콘솔에 에코됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.