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


24

Bash 3과 함께 일하고 있으며 조건부를 만들려고합니다. C / C ++에서 그 간단한 방법은 다음과 같습니다 ((A || B) && C). Bash에서 그 결과는 그렇지 않았습니다.

작동하지 않습니다. 참고 <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 `[['

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

((A || B) && C)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

답변:


42

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 bracket primer가 유용 할 수 있습니다 .

[일반 쉬에서 사용할 수 있습니다. [[그리고 ((bash는 (그리고 KSH 및 zsh을)에 따라 다릅니다.

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


고마워 Giles. 이것은 Bash 2에서 Bash 4까지 유지됩니까? 나는 약간 휴대 뭔가가 필요하지만, Kusalananda 내가 한 몇 가지 언급 하지 수행을 이식 (즉, 내가 무엇을하고 있는가하는 것은 의미 않습니다 하지 휴대용?). 여기서, 약간 배시 배시 통해 제 2 수단

@jww [[ … ]]는 bash 2.02에 추가되었습니다. ((…))bash 2.0에 추가되었습니다.
Gilles 'SO- 악의를 멈춰라'

@ 길리스-감사합니다. 배쉬 2는 아마도 대부분 웃을 수 있습니다. 그것은 우리의 거버넌스와 오래된 플랫폼을 포기하지 않기 때문입니다. Bash 2와 GCC 3은 Fedora 1 테스트에 표시됩니다. 구식 플랫폼을 간혹 사용할 수 있지만 그 이유가있을 수 있습니다. Apple, Microsoft, Mozilla 등의 포기 정책에는 가입하지 않습니다.

@jww 그의 우선 순위 양해 해 주시기 바랍니다 ||&&에서 변화 [[[((. 동등한 우선 순위[(사용 괄호 평가 순서를 제어한다)하지만, 더 높은 우선 순위를 갖는다 && [[((이상 ||(C에서와 같이).

6

사용 [[:

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

원하는 경우 [다음이 작동합니다.

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

3

-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, 그러나 나는 그들과 함께 실험을하지 않았다. 스택 오버플로의 누군가가 그것을 피한다고 말했습니다. 스크립트를 사용하여 읽을 수 없기 때문에 대부분 동의했습니다.

...하지만 더 휴대 가능합니다.
Kusalananda

@Kusalananda-이식성에 대한 헤즈 업에 감사드립니다. 스크립트는 Bash 2부터 Bash 4까지의 시스템에서 실행해야합니다. [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]문제가 있습니까?

당신 bash이 이해하는 다른 쉘이나 다른 쉘에 문제가 없을 것 [[ ... ]]입니다.
Kusalananda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.