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あなたが使用する必要がある((...))上で算術演算を行うことexprlet読みやすさのために。

移植性のために$((...))@Bernhard answerのように使用します


1
+1さらに読みやすく!私は質問と回答を投稿して、仲間のLinuxユーザーに役立つと考えましたが、今では他の回答から多くの利益を得ています:
ニコラスラウル14

3
を使用する理由はありませんlet。これは、標準またはポータブルではなく(( a = 3 * (2 + 1) ))(両方ともkshksh、bash、およびzshでのみ利用可能です)、読みにくく、引用も簡単です。a=$((3 * (2 + 1)))ポータブルにするために使用します。
ステファンシャゼル14

2
私はそれが間違っていると言っているのではなく、より良い代替手段(読みやすさ((a = 3 * (2 + 1) ))、移植性のa=$((3 * (2 + 1)))ためのもの)があるので使用すべきではないと言っているので、それはあなたまたはあなたの答えに対するメモではなく、選択された答えであることに対するものではありませんそして最高得点。
ステファンシャゼル14

@StéphaneChazelas:答えを更新しました!
クオンルム14

a=1 $[a+2]またはを常に使用していa=1 b=2 $[a+b]ます。その構文を避ける理由はありますか?
ゴードン

74

代わりに算術展開を使用できます。

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

私の意見では、これはを使用するよりも少し見た目がいいですexpr

から man bash

算術展開 算術展開により、算術式の評価と結果の置換が可能になります。算術展開の形式は次のとおりです。

         $((expression))

式は二重引用符内にあるかのように扱われますが、括弧内の二重引用符は特別に扱われません。式内のすべてのトークンは、パラメーターの展開、文字列の展開、コマンドの置換、および引用の削除を受けます。算術展開はネストできます。

評価は、算術評価で以下にリストされているルールに従って実行されます。式が無効な場合、bashは失敗を示すメッセージを出力し、置換は行われません。


1
読みやすさは別として、算術を行うために余分なプロセスをフォークする必要もありません。シェル自体によって処理されます。
chepner

POSIXシェルでは、単語分割の対象となるため、リストコンテキストで引用することをお勧めします。
ステファンシャゼラス14

bashシェルでこれを試すと、「無効な変数名」が表示されます。」
lordhog

40

expr現代のシェルで算術演算に使用する理由はありません。

POSIXは$((...))展開演算子を定義します。したがって、すべてのPOSIX準拠のシェル(shすべての最新のUnixライクなもの、ダッシュ、バッシュ、ヤッシュ、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そして、((...))でのみ利用可能ですkshzshbash$((...))構文は、他のシェルへの移植が必要な場合、好まれるべきでexprのみプレPOSIXボーン状シェル(典型的にはBourneシェルまたはAlmquistシェルの初期バージョン)のために必要とされます。

非Bourneフロントには、算術演算子が組み込まれたいくつかのシェルがあります。

  • csh/ tcsh(実際には算術評価が組み込まれた最初のUnixシェル):

    @ a = 3 * (2 + 1)
  • akanga(に基づいてrc

    a = $:'3 * (2 + 1)'
  • 履歴メモとして、1989年にusenetに投稿されたAlmquistシェルのオリジナルバージョンにはexpr組み込みがありましたが(実際にはにマージされましたtest)、後で削除されました。


ステファン、あなたから毎日何か新しいことを学びます。POSIXシェルの知識に感謝します!
MattBianco 14

どう: $((a = a*2))
Arthur2e5

浮動小数点がある場合はどうなりますか?私の式はa = $((-14 + 0.2 *(1 + 2 + 3)))です。エラートークンは「.2 *(1 + 2 + 3)」です
ブレイズ

@ Blaise、$((...))zsh、ksh93、yashなどの浮動小数点をサポートするシェルが必要です。
ステファンシャゼラス

16

expr外部コマンドであり、特別なシェル構文ではありません。したがって、exprシェルの特殊文字を表示する場合は、引用符で囲むことでシェルの解析から保護する必要があります。さらに、expr各数値と演算子を個別のパラメーターとして渡す必要があります。副<文>この[前述の事実の]結果として、それ故に、従って、だから◆【同】consequently; therefore <文>このような方法で、このようにして、こんなふうに、上に述べたように◆【同】in this manner <文>そのような程度まで<文> AひいてはB◆【用法】A and thus B <文>例えば◆【同】for example; as an example:

expr 3 \* \( 2 + 1 \)

1970年代または1980年代のアンティークUnixシステムで作業しているのでない限り、を使用する理由はほとんどありませんexpr。昔は、シェルには算術演算を実行する組み込みの方法がexprなく、代わりにユーティリティを呼び出す必要がありました。すべてのPOSIXシェルには、算術展開構文による算術が組み込まれています。

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

コンストラクト$((…))は、算術式の結果(10進数で記述)に展開されます。Bashは、ほとんどのシェルと同様に、2 64を法とする整数演算のみをサポートします(32ビットマシン上の古いバージョンのbashおよびその他のシェルの場合は2 32を法とする)。

Bashには、割り当てを実行したり、式が0であるかどうかをテストしたいが結果を気にしたくない場合に便利な構文が追加されています。この構造はkshとzshにも存在しますが、プレーンなshには存在しません。

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

整数演算に加えexprて、いくつかの文字列操作関数を提供します。これらもPOSIXシェルの機能に含まれていますが、1つを除きexpr STRING : REGEXPます:文字列が指定された正規表現に一致するかどうかをテストします。POSIXシェルは外部ツールなしでこれを行うことはできませんが、bashは[[ STRING =~ REGEXP ]]別の正規表現構文で —  expr古典的なツールであり、BREを使用し、bashはEREを使用します)使用できます。

20年前のシステムで実行されるスクリプトを保守しているのでなければ、それがexpr存在することを知る必要はありません。シェル演算を使用します。


expr foo : '\(.\)'テキスト抽出も行います。bashBASH_REMATCHようなものを達成します。また、POSIX [が実行しない文字列比較も実行します(sortそのための使用方法は想像できますが)。
ステファンシャゼル14

構文のプレースホルダーとしての下線---あなたはSchemer、@ Giles?:]
RubyTuesdayDONO

1
@RubyTuesdayDONOここではアンダースコアを使用しませんでした。U + 2026 HORIZONTAL ELLIPSISを読み間違えていますか?その場合は、より大きなフォントを使用してみてください。
ジル「SO-悪であるのをやめる」

@Giles —わかりました、はい、フォントサイズのためにアンダースコアのように見えます。私にとっては、「スキーマー」とは、補体であり、アンダースコア対省略記号は、とにかく意味が変わらない...その上に不機嫌を取得する必要が好きではないです:/
RubyTuesdayDONO

12

引用符付きの括弧を使用します。

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

引用符は、bashが括弧をbash構文として解釈するのを防ぎます。


2
Nicolasが示しているが説明していないのは、exprコマンドラインのトークンをスペースで区切る必要があるということです。そう; たとえば、expr 3 "*" "(2" "+" "1)" 動作しません。(また、ところで、あなたはおそらく引用する必要はありません+。)
G-マンは「元に戻すモニカ言う

括弧は次のようなキーワードではありませんwhile[[、彼らは構文です。それらがキーワードである場合、コマンド引数ではそのように解釈されません。bashがそれらを解析せず、代わりに文字列リテラルを見るために引用符が必要です。
ジル 'SO-悪であるのをやめる'

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.