expr
は括弧が好きではないようです(使用数学で明示的な演算子の優先順位に):
expr 3 * (2 + 1) bash: syntax error near unexpected token `("
bashで演算子の優先順位を表現する方法
回答
let
bash組み込みを使用する別の方法:
$ let a="3 * (2 + 1)" $ printf "%s\n" "$a" 9
注
@StéphaneChazelasが指摘したように、bash
では、((...))
を使用してexpr
または読みやすさのためにlet
。
移植性のために、 divのように$((…))
を使用します。 > @Bernhard回答。
コメント
回答
代わりに算術展開を使用できます。
echo "$(( 3 * ( 2 + 1 ) ))" 9
私の個人的な意見では、これはexpr
を使用するよりも少し見栄えがします。
man bash
算術拡張算術展開により、算術式の評価と結果の置換が可能になります。算術展開の形式は次のとおりです。
$((expression))
式は二重引用符で囲まれているように扱われますが、括弧内の二重引用符は特別に扱われません。式内のすべてのトークンは、パラメーター展開、文字列展開、コマンド置換、および引用符の削除を受けます。算術展開はネストできます。
評価は、以下の算術評価のルールに従って実行されます。式が無効な場合、bashは失敗を示すメッセージを出力し、置換は発生しません。
コメント
- 読みやすさは別として、'算術演算を行うために追加のプロセスをフォークする必要もありません。 'はシェル自体によって処理されます。
- POSIXシェルでは、'は単語の対象となることに注意してください。分割するので、'リストコンテキストで引用するのが良い習慣です。
- bashシェルでこれを試すと、変数名が無効です。"
回答
最新のシェルの演算にexpr
を使用する理由はありません。
POSIXは$((...))
を定義しています。拡張演算子。したがって、POSIX準拠のすべてのシェル(ダッシュ、bash、yash、mksh、zsh、posh、kshなどの最新のUnixのsh
で使用できます。 )。
a=$(( 3 * (2 + 1) )) a=$((3*(2+1)))
ksh
もlet
ビルトインを導入しました。同じ種類の算術式が渡され、何かに展開されませんが、式が解決されるかどうかに基づいて終了ステータスを返しますexpr
のように、esを0にするかどうか:
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
および
。$((...))
構文は、他のシェルへの移植性が必要な場合に推奨されます。expr
は、POSIX以前のBourneのようなシェル(通常はBourneシェルまたはAlmquistシェルの初期バージョン)。
Bourne以外のフロントには、算術演算子が組み込まれたシェルがいくつかあります。
-
csh
/tcsh
(実際には、算術評価が組み込まれた最初のUnixシェル):@ a = 3 * (2 + 1)
-
akanga
(rc
に基づく)a = $:"3 * (2 + 1)"
-
履歴メモとして、1989年にusenetに投稿されたAlmquistシェルの元のバージョンには
expr
ビルトイン(実際にはtest
とマージされています)が、後で削除されました。
コメント
- St é phaneさんから毎日新しいことを学びます。 POSIXシェルの知識に感謝します!
-
: $((a = a*2))
はどうですか? - 浮動小数点がある場合はどうなりますか?私の式はa = $((-14 + 0.2 *(1 + 2 + 3)))です。エラートークンは" .2 *(1 + 2 + 3)"
- @Blaiseです。 ' dには、zsh、ksh93、yashなどの
$((...))
の浮動小数点をサポートするシェルが必要です。
回答
expr
は外部コマンドであり、特別なシェル構文ではありません。したがって、expr
にシェルの特殊文字を表示させたい場合は、それらを引用してシェルの解析から保護する必要があります。さらに、expr
では、各数値と演算子を個別のパラメーターとして渡す必要があります。したがって:
expr 3 \* \( 2 + 1 \)
1970年代または1980年代の旧式のUNIXシステムで作業している場合を除き、。昔は、シェルには算術演算を実行する組み込みの方法がなく、代わりに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
は、いくつかの文字列操作関数を提供します。これらも、1つを除いて、POSIXシェルの機能に含まれています。expr STRING : REGEXP
は、文字列が指定されたregexpと一致するかどうかをテストします。POSIXシェルは、これがないと実行できません。外部ツールですが、bashは[[ STRING =~ REGEXP ]]
(異なるregexp構文 — expr
は古典的なツールであり、BREを使用し、bashはEREを使用します。
スクリプトを保守している場合を除きます。 20年前のシステムで実行されている場合は、expr
が存在したことを知る必要はありません。シェル演算を使用します。
コメント
-
expr foo : '\(.\)'
もテキスト抽出を行います。bash
'のBASH_REMATCH
も同様のことを実現します。また、POSIX[
では実行されない文字列比較も実行します(ただし、sort
を使用する方法を想像することはできます)。 - 構文プレースホルダーとしてのアンダースコア—あなたはSchemer、@ Giles? :]
- @RubyTuesdayDONOここではアンダースコアを使用しませんでした'。 U + 2026 HORIZONTAL ELLIPSISを読み間違えていますか?その場合は、より大きなフォントを使用してみてください。
- @Giles —はい、フォントサイズが原因で、アンダースコアのように見えます。私にとって、"スキーマ"は補足であり、'は省略記号とは異なります。対アンダースコアはとにかく意味を変えます…それについて卑劣になる必要はありません:/
答え
括弧を使用して引用符:
expr 3 "*" "(" 2 "+" 1 ")" 9
引用符は、bashが括弧をbash構文として解釈するのを防ぎます。
コメント
- Nicolasが説明しているが説明していないのは、
expr
コマンドラインのトークンはスペースで区切る必要があるということです。そう;たとえば、expr 3 "*" "(2" "+" "1)"
は機能しません 。 (また、ところで、おそらく+
を引用する必要はありません。) - 括弧は'
while
や[[
、それらは'構文です。 それらがキーワードである場合、コマンド引数では'そのように解釈されません。 bashが'を解析せず、代わりに文字列リテラルを表示するように、引用符が必要です。
回答
bcがある場合..
echo "3 * (2 + 1)"|bc 9
let
を使用する理由はありません。 'は(( a = 3 * (2 + 1) ))
(どちらもksh
からのもの)よりも標準的または移植性がありません。 ksh、bash、zshでのみ利用可能です)、'読みにくく、引用しにくいです。a=$((3 * (2 + 1)))
を使用して移植性を高めます。((a = 3 * (2 + 1) ))
、1つ移植性のためにa=$((3 * (2 + 1)))
)、それで'はあなたやあなたの答えに対するメモではなく、選択された答えと最高得点者に対するメモです。a=1 $[a+2]
またはa=1 b=2 $[a+b]
。その構文を避ける理由はありますか?