expr 산술의 괄호 : 3 * (2 + 1)


60

expr 괄호를 좋아하지 않는 것 (수학에서 명시적인 연산자 우선 순위로 사용) :

expr 3 * (2 + 1)
bash: syntax error near unexpected token `('

bash에서 연산자 우선 순위를 표현하는 방법은 무엇입니까?

답변:


40

letbash 내장 을 사용하는 다른 방법 :

$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9

노트

따라 @ 스테판 Chazelas가 지적 에, bash당신이 사용해야 ((...))이상의 연산을 수행 expr하거나 let가독성을 위해.

이식성을 위해 @Bernhard answer$((...)) 와 같이 사용하십시오 .


1
+1 더 읽기 쉬운! 나는 내 리눅스 리눅스 사용자들에게 도움이 될 것이라고 생각하는 질문 + 답변을 게시했지만 이제는 다른 답변으로부터 많은 혜택을 얻고 있습니다 :-)
— Nicolas Raoul

3
를 사용할 이유가 없습니다 let. (( a = 3 * (2 + 1) ))( kshksh, bash 및 zsh에서 제공되며 ksh, bash 및 zsh에서만 사용 가능) 보다 표준 또는 휴대용이 아니며 읽기 어렵거나 인용하기가 쉽지 않습니다. a=$((3 * (2 + 1)))휴대용으로 사용하십시오 .
— Stéphane Chazelas

2
나는 그것이 틀렸다고 말하는 것이 아니라 더 나은 대안이 있기 때문에 사용해서는 안된다는 것을 말하고있는 것입니다 (가독성 ((a = 3 * (2 + 1) )), 이식성에 대한 대안 a=$((3 * (2 + 1)))). 따라서 당신이나 당신의 대답에 대한 메모가 아니라 선택된 대답에 반대합니다. 그리고 최고 득점자.
— Stéphane Chazelas

@ StéphaneChazelas : 내 답변을 업데이트했습니다!
— cuonglm

나는 항상 a=1 $[a+2]또는을 사용했다 a=1 b=2 $[a+b]. 그 구문을 피해야하는 이유입니까?
— 고든

74

대신 산술 확장을 사용할 수 있습니다.

echo "$(( 3 * ( 2 + 1 ) ))"
9

내 개인적인 견해로는을 사용하는 것보다 조금 더 좋아 보입니다 expr.

에서 man bash

산술 확장 산술 확장을 통해 산술 표현식을 평가하고 결과를 대체 할 수 있습니다. 산술 확장 형식은 다음과 같습니다.

         $((expression))

표현식은 큰 따옴표 안에있는 것처럼 처리되지만 괄호 안의 큰 따옴표는 특별히 처리되지 않습니다. 표현식의 모든 토큰은 매개 변수 확장, 문자열 확장, 명령 대체 및 따옴표 제거를 거칩니다. 산술 확장이 중첩 될 수 있습니다.

평가는 산술 평가 아래에 나열된 규칙에 따라 수행됩니다. expression이 유효하지 않으면 bash는 실패를 나타내는 메시지를 인쇄하고 대체가 발생하지 않습니다.


1
가독성 외에도 산술을 위해 추가 프로세스를 요구하지 않습니다. 쉘 자체에 의해 처리됩니다.
— chepner

POSIX 쉘에서는 단어 분할이 적용되므로 목록 컨텍스트에서 인용하는 것이 좋습니다.
— Stéphane Chazelas

bash 쉘에서 이것을 시도하면 '잘못된 변수 이름'을 얻습니다.
— lordhog

40

expr현대 쉘에서 산술에 사용할 이유가 없습니다 .

POSIX는 $((...))확장 연산자를 정의합니다 . 따라서 모든 POSIX 호환 쉘 ( sh모든 현대 유닉스 계열, 대시, bash, yash, mksh, zsh, posh, ksh ...)에서 사용할 수 있습니다.

a=$(( 3 * (2 + 1) ))
a=$((3*(2+1)))

ksh또한 let같은 종류의 산술 표현식이 전달되고 무언가로 확장되지 않고 표현식이 0으로 해석되는지 여부에 따라 종료 상태를 반환 하는 내장 기능을 도입 했습니다 expr.

if let 'a = 3 * (2 + 1)'; then
  echo "$a is non-zero"
fi

그러나 인용문이 어색하고 이해하기 쉽지 않기 때문에 ( expr물론 같은 정도는 아님) 대체 형식 ksh도 도입했습니다 ((...)).

if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then
  echo "$a is non-zero and 3 > 1"
fi
((a+=2))

훨씬 더 읽기 쉬우 며 대신 사용해야합니다.

let및 ((...))에서만 사용할 수 있습니다 ksh, zsh그리고 bash. $((...))다른 쉘로의 이식성이 필요한 경우 , 구문은 exprPOSIX 이전 Bourne 유사 쉘 (일반적으로 Bourne 쉘 또는 Almquist 쉘의 초기 버전)에만 필요합니다.

Bourne이 아닌 프론트에는 내장 된 산술 연산자가있는 몇 개의 쉘이 있습니다.

  • csh/ tcsh(실제로 산술 평가 기능이 내장 된 최초의 유닉스 쉘) :

    @ a = 3 * (2 + 1)
  • akanga(기준 rc)

    a = $:'3 * (2 + 1)'
  • 1989 년에 유즈넷에 게시 된 Almquist 쉘의 원래 버전은 기본적으로 expr내장되어 test있었지만 (실제로 병합 됨 ) 나중에 제거되었습니다.


스테판은 매일 새로운 것을 배웁니다. POSIX 쉘 지식에 대단히 감사합니다!
— MattBianco

어때요 : $((a = a*2))?
— Arthur2e5

부동 소수점이 있으면 어떻게합니까? 내 표현은 a = $ ((-14 + 0.2 * (1 + 2 + 3)))입니다. 에러 토큰은 ".2 * (1 + 2 + 3)"입니다.
— Blaise

@Blaise, $((...))zsh, ksh93 또는 yash와 같은 부동 소수점을 지원하는 셸이 필요합니다 .
— Stéphane Chazelas

16

expr외부 명령이며 특수 쉘 구문이 아닙니다. 따라서 expr쉘 특수 문자를 보려면 인용 부호를 사용하여 쉘 구문 분석으로부터 보호해야합니다. 또한 expr각 숫자와 연산자를 별도의 매개 변수로 전달해야합니다. 그러므로:

expr 3 \* \( 2 + 1 \)

1970 년대 또는 1980 년대의 골동품 유닉스 시스템을 사용하지 않는 한, 사용할 이유가 거의 없습니다 expr. 예전에는 셸에 산술을 수행하는 기본 제공 방법이 없었으므로 expr대신 유틸리티 를 호출해야 했습니다. 모든 POSIX 쉘에는 산술 확장 구문을 통해 내장 된 산술이 있습니다.

echo "$((3 * (2 + 1)))"

구조 $((…))는 산술 연산 결과 (10 진수로 표시됨)로 확장됩니다. 대부분의 셸과 마찬가지로 Bash는 정수 산술 모듈로 2 64 (또는 이전 버전의 bash 및 32 비트 시스템의 다른 셸의 경우 모듈로 2 32) 만 지원합니다 .

배시는 할당을 수행하거나 표현식이 0인지 여부를 테스트하지만 결과에 신경 쓰지 않을 때 추가 편의 구문을 제공합니다 . 이 구조는 ksh와 zsh에도 존재하지만 일반 sh에는 존재하지 않습니다.

((x = 3 * (2+1)))
echo "$x"
if ((x > 3)); then …

정수 산술 외에도 expr몇 가지 문자열 조작 기능을 제공합니다. 이것들도 POSIX 쉘의 기능에 의해 제외되고, 하나를 제외하고 : expr STRING : REGEXP문자열이 지정된 정규 표현식과 일치하는지 테스트합니다. 는 POSIX 쉘은 외부 도구없이이 작업을 수행 할 수 있지만, bash는 함께 할 수 [[ STRING =~ REGEXP ]]의 (a와 다른 정규 표현식 구문 -  expr고전적인 도구입니다 BRE를 사용 배쉬는 ERE를 사용합니다).

20 년 된 시스템에서 실행되는 스크립트를 유지 관리하지 않는 한 기존 스크립트를 알 필요는 없습니다 expr. 쉘 산술을 사용하십시오.


expr foo : '\(.\)'텍스트 추출도 수행합니다. bash의는 BASH_REMATCH비슷한을 달성한다. 또한 POSIX [가하지 않는 문자열 비교를 수행합니다 (물론 사용 방법을 상상할 수 sort는 있음).
— Stéphane Chazelas

구문 자리 표시 자로 밑줄 --- Schemer, @Giles? :]
— RubyTuesdayDONO

1
@RubyTuesdayDONO 나는 밑줄을 사용하지 않았습니다. U + 2026 HORIZONTAL ELLIPSIS를 잘못 읽고 있습니까? 그렇다면 더 큰 글꼴을 사용해보십시오.
— Gilles

@Giles — 예, 폰트 크기 때문에 밑줄처럼 보입니다. 나를 위해, "음모"는 보완, 그것은 생략 대 밑줄이 ... 어쨌든 그 위에 snarky받을 필요 의미를 변경하지처럼하지 : /
— RubyTuesdayDONO

12

따옴표와 함께 괄호를 사용하십시오.

expr 3 '*' '(' 2 '+' 1 ')'
9

따옴표는 bash가 괄호를 bash 구문으로 해석하지 못하게합니다.


2
Nicolas가 설명하지만 설명하지 않은 것은 expr명령 행 의 토큰 이 공백으로 분리되어야한다는 것입니다. 그래서; 예를 들어 expr 3 "*" "(2" "+" "1)" 작동하지 않습니다 . (또한 BTW, 당신은 아마 인용 할 필요가 없습니다 +.)
— G-Man

괄호는 whileand와 같은 키워드가 아니며 [[구문입니다. 키워드 인 경우 명령 인수에서 해석되지 않습니다. bash가 구문 분석하지 않고 대신 문자열 리터럴을 볼 수 있도록 따옴표가 필요합니다.
— Gilles

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