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.