여러 논리 연산자, ((A || B) & & C) 및 “ 예기치 않은 토큰 근처의 구문 오류 ”

저는 Bash 3을 사용하고 있으며 조건부를 형성하십시오. C / C ++에서는 아주 간단합니다 : ((A || B) && C). Bash에서는 그렇지 않습니다 (Git 작성자가 다른 작업으로 이동하기 전에이 코드를 제공했을 것입니다).

이것은 작동하지 않습니다. <0 or 1>는 문자열 리터럴이 아닙니다. 0 또는 1을 의미합니다 (일반적으로 grep -i에서 가져옴).

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eqe "0" ]; then ... fi 

결과 :

line 322: syntax error near unexpected token `[[" 

그런 다음 시도 :

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ ([ "$A" -eq "0" ]) || ([ "$B" -ne "0" ]) ] && [ "$C" -eq "0" ]; then ... fi 

결과 :

line 322: syntax error near unexpected token `[[" 

문제의 일부는 검색 결과가 사소한 예이며 복합 조건이있는 더 복잡한 예가 아니라는 것입니다.

간단한

Bash에서?


그냥 펴서 여러 블록에서 동일한 명령을 반복 할 준비가되었습니다.

A=<0 or 1> B=<0 or 1> C=<0 or 1> if [ "$A" -eq "0" ] && [ "$C" -eq "0" ]; then ... elif [ "$B" -ne "0" ] && [ "$C" -eq "0" ]; then ... fi 

Answer

bash의 구문은 C에서 영감을받은 일부라도 C와 비슷하지 않습니다. 단순히 C 코드를 작성하고 작동 할 것으로 기대할 수는 없습니다.

쉘의 핵심은 명령을 실행하는 것입니다. 대괄호 열기 명령 [은 단일 테스트를 수행하는 명령입니다 ¹. 마지막 닫는 대괄호없이 test로 쓸 수도 있습니다. ||&& 연산자는 셸 연산자이며 테스트가 아닌 명령 을 결합합니다.

그래서

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ] 

그것이 다음과 같이 파싱 될 때

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ] 

다음과 같습니다.

test [ "$A" -eq "0" || test "$B" -ne "0" ] && test "$C" -eq "0" 

불균형 괄호에 주목하십니까? 예, 좋지 않습니다. 괄호를 사용한 시도는 동일한 문제가 있습니다. 가짜 대괄호

명령어를 그룹화하는 구문은 중괄호입니다. 중괄호가 구문 분석되는 방식은 그 앞에 완전한 명령이 필요하므로 “중괄호 안의 명령을 줄 바꿈 또는 세미콜론으로 종료해야합니다.

if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then … 

거기 “이중 대괄호를 사용하는 다른 방법입니다. 단일 대괄호와 달리 이중 대괄호는 특수 쉘 구문입니다. 조건식 을 구분합니다. 이중 괄호 안에는 &&||와 같은 괄호와 연산자를 사용할 수 있습니다. 이중 괄호는 셸 구문이므로 셸은 이러한 연산자가 괄호 안에있을 때 “일반 셸 명령 구문의 일부가 아니라 조건식 구문의 일부임을 알고 있습니다.

if [[ ($A -eq 0 || $B -ne 0) && $C -eq 0 ]]; then … 

모든 테스트가 숫자 인 경우 관절 식 을 구분하는 또 다른 방법이 있습니다. 산술 표현식은 C와 유사한 구문으로 정수 계산을 수행합니다.

if (((A == 0 || B != 0) && C == 0)); then … 

내 bash 대괄호를 찾을 수 있습니다. 입문서 가 유용합니다.

[는 일반 sh에서 사용할 수 있습니다. [[((는 bash (및 ksh 및 zsh)에만 해당됩니다.

¹ 또한 가능합니다. 여러 테스트를 부울 연산자와 결합하지만 사용하기가 번거롭고 미묘한 함정이 있으므로 설명하지 않겠습니다.

댓글

  • Giles에게 감사합니다. Bash 2부터 Bash 4까지 적용됩니까? 약간의 이식성이 필요하지만 Kusalananda는 내가하고 있지 않는 일이 이식 가능하다고 언급했습니다 (내가하는 일이 휴대용이 아님 ). 여기서 약간 은 Bash 2에서 Bash 4까지를 의미합니다.
  • @jww [[ … ]]가 추가되었습니다. bash 2.02에서. ((…))가 bash 2.0에 추가되었습니다.
  • @Giles-감사합니다. Bash 2는 아마도 대부분의 사람들에게 웃을 것입니다. 이는 우리의 거버넌스와 꺼림칙 함 때문입니다. 이전 플랫폼을 포기합니다. Bash 2 및 GCC 3이 Fedora 1 테스트에 나타납니다. 때때로 이전 플랫폼을 사용할 수 있지만 그럴만 한 이유가 있습니다. 우리는 ' Apple, Microsoft, Mozilla 등의 포기 정책을 구독하지 마십시오.
  • @jww ||[에서 [[((로 변경합니다. [ 우선 순위 와 같지만 (평가 순서를 제어하려면 괄호 사용) & &는 [[((에서

    (C에서와 같음)

  • @Roland 아니요, [[ … ]] 또는 $((…))는 그룹화 전용입니다.

답변

[[ 사용 :

if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ... 

[를 선호하는 경우 다음이 작동합니다.

if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ... 

댓글

  • 감사합니다, Stephen. 제 경우에는 첫 번째 예제를 사용했습니다 … regex = ' ^ [0-9] + $ ' length = $ {#datearg} if! [[$ datearg = ~ $ regex & & $ length -eq 8]]; then echo " 오류 : 8의 길이가 아닙니다 "; fi

Answer

대신 -o 연산자를 사용하세요. 중첩 ||. 필요한 경우 -a를 사용하여 & &를 대체 할 수도 있습니다. .

 EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true if [ "$A" -eq "0" -o "$B" -ne "0" ] && [ "$C" -eq "0" ]; then echo success;fi 

댓글

  • 감사합니다. -a-o를 발견했지만 실험하지는 않았습니다. Stack Overflow의 누군가가 그것을 피하라고 말했습니다. 나는 스크립트를 사용하면 스크립트를 읽을 수 없기 때문에 대부분 동의했습니다.
  • …하지만 이식성이 더 뛰어납니다.
  • @Kusalananda-이식성에 대한 경고에 감사드립니다. 스크립트는 Bash 2부터 Bash 4까지의 시스템에서 실행되어야합니다. [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]에 문제가 있습니까?
  • bash 또는 [[ ... ]]를 이해하는 다른 셸
  • -a 사용의 단점은 ' 첫 번째 표현이 거짓이면 단락하지 않습니다. 따라서 잠재적 인 치명적인 두 번째 표현식이 실행되는 것을 방지하기 위해 단락에 의존하는 경우 -a를 사용할 수 없습니다. 예 : pastebin.com/zM77TXW1

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다